home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Sources / Tiling.c < prev   
Encoding:
Text File  |  2000-10-06  |  88.6 KB  |  3,006 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    Tiling.c
  3. //
  4. //    By Vern Jensen. SWLoadTile routines by Karl Bunker.
  5. //    
  6. //    Created: 11/15/95
  7. //
  8. //    Description:    Routines to use tiling with SpriteWorld
  9. ///--------------------------------------------------------------------------------------
  10.  
  11.  
  12. #ifndef __QUICKDRAW__
  13. #include <QuickDraw.h>
  14. #endif
  15.  
  16. #ifndef __RESOURCES__
  17. #include <Resources.h>
  18. #endif
  19.  
  20. #ifndef __MEMORY__
  21. #include <Memory.h>
  22. #endif
  23.  
  24. #ifndef __SPRITEWORLD__
  25. #include <SpriteWorld.h>
  26. #endif
  27.  
  28. #ifndef __SPRITEFRAME__
  29. #include <SpriteFrame.h>
  30. #endif
  31.  
  32. #ifndef __SPRITEWORLDUTILS__
  33. #include <SpriteWorldUtils.h>
  34. #endif
  35.  
  36. #ifndef __TILING__
  37. #include <Tiling.h>
  38. #endif
  39.  
  40. #ifndef __BLITPIXIEINTERFACE__
  41. #include <BlitPixieInterface.h>
  42. #endif
  43.  
  44.  
  45.  
  46. ///--------------------------------------------------------------------------------------
  47. //    SWInitTiling - Note: Whenever changing this function, change the sister function in
  48. //    Multi-Screen Scrolling.c too!
  49. ///--------------------------------------------------------------------------------------
  50.  
  51. SW_FUNC OSErr SWInitTiling(
  52.     SpriteWorldPtr    spriteWorldP,
  53.     short             tileHeight,
  54.     short            tileWidth,
  55.     short            maxNumTiles)
  56. {
  57.     OSErr     err = noErr;
  58.     Size    arraySize;
  59.     short    tileIndex;
  60.     
  61.     SW_ASSERT(spriteWorldP != NULL);
  62.     
  63.     if (spriteWorldP->tilingIsInitialized)
  64.     {
  65.         err = kTilingAlreadyInitialized;
  66.     }
  67.     
  68.     
  69.     if (err == noErr)
  70.     {
  71.         spriteWorldP->tilingIsOn = true;
  72.         spriteWorldP->tilingIsInitialized = true;
  73.         spriteWorldP->lastActiveTileLayer = 0;
  74.         spriteWorldP->maxNumTiles = maxNumTiles;
  75.         spriteWorldP->tileHeight = tileHeight;
  76.         spriteWorldP->tileWidth = tileWidth;
  77.     }
  78.     
  79.     
  80.     if (err == noErr)
  81.     {
  82.             // Create both tiling cache and changedTiles array of rects
  83.         err = SWInitTilingCache(spriteWorldP);
  84.     }
  85.     
  86.     
  87.     if (err == noErr)
  88.     {
  89.             // Allocate memory for tileFrameArray
  90.         arraySize = (Size)maxNumTiles * sizeof(FramePtr);
  91.         spriteWorldP->tileFrameArray = (FramePtr *)NewPtrClear(arraySize);
  92.         err = MemError();
  93.     }
  94.     
  95.     
  96.     if (err == noErr)
  97.     {
  98.             // Allocate memory for curTileImage array
  99.         arraySize = (Size)maxNumTiles * sizeof(short);
  100.         spriteWorldP->curTileImage = (short *)NewPtr(arraySize);
  101.         err = MemError();
  102.         
  103.         if (err == noErr)
  104.         {
  105.                 // Set up values in curTileImage array
  106.             for (tileIndex = 0; tileIndex < maxNumTiles; tileIndex++)
  107.                 spriteWorldP->curTileImage[tileIndex] = tileIndex;
  108.         }
  109.     }
  110.     
  111.     
  112.     if (err == noErr)
  113.     {
  114.             // Allocate memory for tileLayerArray
  115.         arraySize = (Size)kNumTileLayers * sizeof(TileMapStructPtr);
  116.         spriteWorldP->tileLayerArray = (TileMapStructPtr *)NewPtrClear(arraySize);
  117.         err = MemError();
  118.     }
  119.     
  120.     
  121.     SWSetStickyIfError(err);
  122.     return err;
  123. }
  124.  
  125.  
  126. ///--------------------------------------------------------------------------------------
  127. //    SWExitTiling
  128. ///--------------------------------------------------------------------------------------
  129.  
  130. SW_FUNC void SWExitTiling(
  131.     SpriteWorldPtr    spriteWorldP)
  132. {
  133.     short    tileIndex;
  134.     
  135.     SW_ASSERT(spriteWorldP != NULL);
  136.     
  137.         // Was tiling ever initialized?
  138.     if (spriteWorldP->tilingIsInitialized)
  139.     {
  140.         tileIndex = spriteWorldP->maxNumTiles;
  141.         while (tileIndex--)
  142.         {
  143.             SWDisposeTile(spriteWorldP, tileIndex);
  144.         }
  145.         
  146.         DisposePtr((Ptr)spriteWorldP->tileFrameArray);
  147.         DisposePtr((Ptr)spriteWorldP->curTileImage);
  148.         DisposePtr((Ptr)spriteWorldP->tileLayerArray);
  149.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  150.         spriteWorldP->changedTiles = NULL;
  151.         
  152.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  153.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  154.         spriteWorldP->tilingCache = NULL;
  155.         
  156.                 
  157.         spriteWorldP->tilingIsInitialized = false;
  158.         spriteWorldP->tilingIsOn = false;
  159.     }
  160. }
  161.  
  162.  
  163. ///--------------------------------------------------------------------------------------
  164. //    SWInitTilingCache - an internal function; called by SWInitTiling and SWChangeTileSize.
  165. //    Creates both the tiling cache and the changedTiles array of rects.
  166. ///--------------------------------------------------------------------------------------
  167.  
  168. SW_FUNC OSErr SWInitTilingCache(
  169.     SpriteWorldPtr    spriteWorldP)
  170. {
  171.     short    row, col, numTilingCacheCols, numTilingCacheRows, *tilingCacheData;
  172.     Size    arraySize;
  173.     OSErr    err = noErr;
  174.     
  175.         // Dispose the old tilingCache if necessary
  176.     if (spriteWorldP->tilingCache != NULL)
  177.     {
  178.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  179.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  180.     }
  181.     
  182.         // Dispose the old changeTiles array of rects if necessary
  183.     if (spriteWorldP->changedTiles != NULL)
  184.     {
  185.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  186.     }
  187.     
  188.     numTilingCacheRows = spriteWorldP->backRect.bottom / spriteWorldP->tileHeight;
  189.     numTilingCacheCols = spriteWorldP->backRect.right / spriteWorldP->tileWidth;
  190.     spriteWorldP->numTilingCacheRows = numTilingCacheRows;
  191.     spriteWorldP->numTilingCacheCols = numTilingCacheCols;
  192.     
  193.  
  194.         // Allocate memory for changedTiles array of rects
  195.     spriteWorldP->changedTilesArraySize = (numTilingCacheRows+1) * (numTilingCacheCols+1);
  196.     arraySize = (Size)(numTilingCacheRows+1) * (numTilingCacheCols+1) * sizeof(Rect);
  197.     spriteWorldP->changedTiles = (Rect *)NewPtr(arraySize);
  198.     err = MemError();
  199.     
  200.     
  201.     if (err == noErr)
  202.     {
  203.             // Allocate the array of pointers for the tiling Cache
  204.         arraySize = (Size)numTilingCacheRows * sizeof(short*);
  205.         spriteWorldP->tilingCache = (short **)NewPtr(arraySize);
  206.         err = MemError();
  207.         
  208.         if (err == noErr)
  209.         {
  210.                 // Allocate memory for the actual data of the tiling Cache
  211.             arraySize = (Size)numTilingCacheRows * numTilingCacheCols * sizeof(short);
  212.             tilingCacheData = (short *)NewPtr(arraySize);
  213.             err = MemError();
  214.             
  215.                 // If there was an error, dispose what we already created earlier
  216.             if (err != noErr)
  217.                 DisposePtr((Ptr)spriteWorldP->tilingCache);
  218.         }
  219.         
  220.         if (err == noErr)
  221.         {
  222.                 // Point each element of the tilingCache array to each row of the data
  223.             for (row = 0; row < numTilingCacheRows; row++)
  224.                 spriteWorldP->tilingCache[row] = 
  225.                     &tilingCacheData[(unsigned long)row * numTilingCacheCols];
  226.  
  227.                 // Set all elements to -1 (indicating that each tile needs to be drawn)
  228.             for (row = 0; row < numTilingCacheRows; row++)
  229.                 for (col = 0; col < numTilingCacheCols; col++)
  230.                     spriteWorldP->tilingCache[row][col] = -1;
  231.         }
  232.     }
  233.     
  234.     if (err)
  235.     {
  236.         spriteWorldP->tilingCache = NULL;
  237.         spriteWorldP->changedTiles = NULL;
  238.     }
  239.     
  240.     return err;
  241. }
  242.  
  243.  
  244. ///--------------------------------------------------------------------------------------
  245. //    SWCreateTileMap
  246. ///--------------------------------------------------------------------------------------
  247.  
  248. SW_FUNC OSErr SWCreateTileMap(
  249.     TileMapStructPtr    *tileMapStructPP,
  250.     short                 numTileMapRows,
  251.     short                numTileMapCols)
  252. {
  253.     TileMapStructPtr    tileMapStructP;
  254.     Size                arraySize;
  255.     OSErr                err = noErr;
  256.     
  257.  
  258.         // Allocate memory for the TileMapStruct
  259.     tileMapStructP = (TileMapStructPtr)NewPtrClear(sizeof(TileMapStruct));
  260.     err = MemError();
  261.     
  262.     if (err == noErr)
  263.     {
  264.         tileMapStructP->numRows = numTileMapRows;
  265.         tileMapStructP->numCols = numTileMapCols;
  266.         
  267.             // Allocate the array of pointers that point to the data of the TileMap
  268.         arraySize = (Size)numTileMapRows * sizeof(short*);
  269.         tileMapStructP->arrayOfPointersH = NewHandle(arraySize);
  270.         err = MemError();
  271.     }
  272.     
  273.     if (err == noErr)
  274.     {
  275.             // Allocate memory for the actual data of the TileMap
  276.         arraySize = ((Size)numTileMapRows * numTileMapCols + 2) * sizeof(short);
  277.         tileMapStructP->tileMapDataH = NewHandleClear(arraySize);
  278.         err = MemError();
  279.     }
  280.     
  281.     if (err == noErr)
  282.     {
  283.         SWLockTileMap(tileMapStructP);
  284.     }
  285.     
  286.     
  287.     if (err != noErr)
  288.     {
  289.             // Dispose what we created
  290.         if (tileMapStructP != NULL)
  291.         {
  292.             DisposeHandle((Handle)tileMapStructP->arrayOfPointersH);
  293.             DisposeHandle((Handle)tileMapStructP->tileMapDataH);
  294.             DisposePtr((Ptr)tileMapStructP);
  295.             tileMapStructP = NULL;
  296.         }
  297.     }
  298.  
  299.         // Return a pointer to the TileMapStruct in the tileMapStructPP variable
  300.     *tileMapStructPP = tileMapStructP;
  301.     
  302.     SWSetStickyIfError(err);
  303.     return err;
  304. }
  305.  
  306.  
  307. ///--------------------------------------------------------------------------------------
  308. //    SWDisposeTileMap
  309. ///--------------------------------------------------------------------------------------
  310.  
  311. SW_FUNC void SWDisposeTileMap(
  312.     TileMapStructPtr    *tileMapStructPP)
  313. {
  314.     TileMapStructPtr    myTileMapStructP = *tileMapStructPP;
  315.     
  316.     if (myTileMapStructP != NULL)
  317.     {
  318.         DisposeHandle((Handle)myTileMapStructP->arrayOfPointersH);
  319.         DisposeHandle((Handle)myTileMapStructP->tileMapDataH);
  320.         DisposePtr((Ptr)myTileMapStructP);
  321.         *tileMapStructPP = NULL;
  322.     }
  323. }
  324.  
  325.  
  326. ///--------------------------------------------------------------------------------------
  327. //    SWLockTileMap
  328. ///--------------------------------------------------------------------------------------
  329.  
  330. SW_FUNC void SWLockTileMap(
  331.     TileMapStructPtr    tileMapStructP)
  332. {
  333.     short        **arrayOfPointers;
  334.     short        *tileMapDataP;
  335.     short        row;
  336.     
  337.     SW_ASSERT(tileMapStructP != NULL);
  338.     
  339.     HLockHi(tileMapStructP->arrayOfPointersH);
  340.     HLockHi(tileMapStructP->tileMapDataH);
  341.     
  342.     tileMapDataP = (short*)*tileMapStructP->tileMapDataH;
  343.     arrayOfPointers = (short**)*tileMapStructP->arrayOfPointersH;
  344.  
  345.         // Point each element of the array of pointers to each row of the data
  346.     for (row = 0; row < tileMapStructP->numRows; row++)
  347.     {
  348.             // Note: must use (unsigned long) instead of (long) to avoid a bug in CW's optimizer.
  349.         arrayOfPointers[row] = &tileMapDataP[(unsigned long)row * tileMapStructP->numCols + 2];
  350.     }
  351.     
  352.     tileMapStructP->tileMap = arrayOfPointers;
  353.     tileMapStructP->isLocked = true;
  354. }
  355.  
  356.  
  357. ///--------------------------------------------------------------------------------------
  358. //    SWUnlockTileMap
  359. ///--------------------------------------------------------------------------------------
  360.  
  361. SW_FUNC void SWUnlockTileMap(
  362.     TileMapStructPtr    tileMapStructP)
  363. {
  364.     SW_ASSERT(tileMapStructP != NULL);
  365.     
  366.     HUnlock(tileMapStructP->arrayOfPointersH);
  367.     HUnlock(tileMapStructP->tileMapDataH);
  368.     tileMapStructP->tileMap = NULL;
  369.     tileMapStructP->isLocked = false;
  370. }
  371.  
  372.  
  373. ///--------------------------------------------------------------------------------------
  374. //    SWInstallTileMap
  375. ///--------------------------------------------------------------------------------------
  376.  
  377. SW_FUNC void SWInstallTileMap(
  378.     SpriteWorldPtr        spriteWorldP,
  379.     TileMapStructPtr    tileMapStructP,
  380.     short                tileLayer)
  381. {
  382.     short    curLayer;
  383.     
  384.     SW_ASSERT(spriteWorldP != NULL);
  385.     SW_ASSERT(tileLayer < kNumTileLayers);
  386.     
  387.         // Install the TileMap
  388.     spriteWorldP->tileLayerArray[tileLayer] = tileMapStructP;
  389.     spriteWorldP->lastActiveTileLayer = 0;
  390.     
  391.         // Find the last active tile layer
  392.     for (curLayer = 0; curLayer < kNumTileLayers; curLayer++)
  393.     {
  394.         if (spriteWorldP->tileLayerArray[curLayer] != NULL)
  395.             spriteWorldP->lastActiveTileLayer = curLayer;
  396.     }
  397.     
  398.         // Set the appropriate tileRectDrawProc
  399.     if (spriteWorldP->lastActiveTileLayer == 0)
  400.     {
  401.         spriteWorldP->tileRectDrawProc = SWDrawTilesInRect;
  402.     }
  403.     else
  404.     {
  405.         spriteWorldP->tileRectDrawProc = SWDrawTileLayersInRect;
  406.     }
  407. }
  408.  
  409.  
  410. ///--------------------------------------------------------------------------------------
  411. //    SWLoadTileMap
  412. ///--------------------------------------------------------------------------------------
  413.  
  414. SW_FUNC OSErr SWLoadTileMap(
  415.     ResType                resType,
  416.     TileMapStructPtr    *tileMapStructPP,
  417.     short                 resourceID)
  418. {
  419.     TileMapStructPtr    tileMapStructP;
  420.     short                *tileMapData;
  421.     Size                arraySize;
  422.     OSErr                err = noErr;
  423.     
  424.     
  425.         // Allocate memory for the TileMapStruct
  426.     tileMapStructP = (TileMapStructPtr)NewPtrClear(sizeof(TileMapStruct));
  427.     err = MemError();
  428.     
  429.     if (err == noErr)
  430.     {    
  431.             // Load the resource
  432.         tileMapStructP->tileMapDataH = Get1Resource(resType, resourceID);
  433.         
  434.         if (tileMapStructP->tileMapDataH == NULL)
  435.             err = ResError() ? ResError() : resNotFound;
  436.     }
  437.     
  438.     if (err == noErr)
  439.     {
  440.         DetachResource((Handle)tileMapStructP->tileMapDataH);
  441.         
  442.         tileMapData = (short*)*tileMapStructP->tileMapDataH;
  443.         tileMapStructP->numRows = tileMapData[0];
  444.         tileMapStructP->numCols = tileMapData[1];
  445.         
  446.             // Allocate the array of pointers that point to the data of the TileMap
  447.         arraySize = (Size)tileMapStructP->numRows * sizeof(short*);
  448.         tileMapStructP->arrayOfPointersH = NewHandle(arraySize);
  449.         err = MemError();
  450.     }
  451.     
  452.     if (err == noErr)
  453.     {
  454.         SWLockTileMap(tileMapStructP);
  455.     }
  456.     
  457.     
  458.     if (err != noErr)
  459.     {
  460.             // Dispose what we created
  461.         if (tileMapStructP != NULL)
  462.         {
  463.             DisposeHandle((Handle)tileMapStructP->arrayOfPointersH);
  464.             DisposeHandle((Handle)tileMapStructP->tileMapDataH);
  465.             DisposePtr((Ptr)tileMapStructP);
  466.             tileMapStructP = NULL;
  467.         }
  468.     }
  469.     
  470.         // Return a pointer to the TileMapStruct in the tileMapStructPP variable
  471.     *tileMapStructPP = tileMapStructP;
  472.     
  473.     SWSetStickyIfError(err);
  474.     return err;
  475. }
  476.  
  477.  
  478. ///--------------------------------------------------------------------------------------
  479. //    SWSaveTileMap
  480. ///--------------------------------------------------------------------------------------
  481.  
  482. SW_FUNC OSErr SWSaveTileMap(
  483.     ResType                resType,
  484.     TileMapStructPtr    tileMapStructP,
  485.     short                 destResID)
  486. {
  487.     short        tempResID, oldResID;
  488.     short        *tileMapData;
  489.     Handle        tempTileMapH;
  490.     Str255        oldResName = "\p";
  491.     ResType        oldResType;
  492.     OSErr        err = noErr;
  493.     
  494.         // Make sure there is a tileMap to save
  495.     if (tileMapStructP == NULL)
  496.         err = kNullTileMapErr;
  497.  
  498.     if (err == noErr)
  499.     {
  500.             // Save numRows & numCols in the first two elements of the tileMapData
  501.         tileMapData = (short*)*tileMapStructP->tileMapDataH;
  502.         tileMapData[0] = tileMapStructP->numRows;
  503.         tileMapData[1] = tileMapStructP->numCols;
  504.         
  505.             // Add the TileMap resource, assigning it a temporary, unused ID
  506.         tempResID = Unique1ID(resType);
  507.         AddResource(tileMapStructP->tileMapDataH, resType, tempResID, "\p");
  508.         err = ResError();
  509.     }
  510.     
  511.     if (err == noErr)
  512.     {
  513.         do        // Remove any old TileMap resources with destResID
  514.         {
  515.             SetResLoad(false);
  516.             tempTileMapH = Get1Resource(resType, destResID);
  517.             SetResLoad(true);
  518.             
  519.             if (tempTileMapH != NULL)
  520.             {
  521.                     // Save the name of the resource we're about to replace.
  522.                 GetResInfo(tempTileMapH, &oldResID, &oldResType, oldResName);
  523.                 RemoveResource(tempTileMapH);
  524.                 
  525.                     // This could happen if the resource is protected
  526.                 err = ResError();
  527.                 SW_ASSERT(ResError() == noErr);
  528.             }
  529.             else if (ResError() != resNotFound && ResError() != noErr)
  530.             {
  531.                 // This could happen if Get1Resource didn't have a free master
  532.                 // pointer and there isn't enough memory to allocate a new block
  533.                 err = ResError();
  534.             }
  535.         } while (tempTileMapH != NULL);
  536.         
  537.             // We do this after deleting the old TMAP, but before changing our new 
  538.             // resource's resID to the same as the one we just deleted to avoid serious 
  539.             // problems caused by the Resource Manager if we don't.
  540.         UpdateResFile( CurResFile() );
  541.         
  542.             // Change the resource ID to the proper one. Also restore original res name.
  543.         SetResInfo(tileMapStructP->tileMapDataH, destResID, oldResName);
  544.         ChangedResource(tileMapStructP->tileMapDataH);
  545.         
  546.             // Update file.
  547.         UpdateResFile( CurResFile() );
  548.         DetachResource(tileMapStructP->tileMapDataH);
  549.     }
  550.                 
  551.     
  552.     SWSetStickyIfError(err);
  553.     return err;
  554. }
  555.  
  556.  
  557. ///--------------------------------------------------------------------------------------
  558. //    SWResizeTileMap
  559. ///--------------------------------------------------------------------------------------
  560.  
  561. SW_FUNC OSErr SWResizeTileMap(
  562.     TileMapStructPtr    oldTileMapStructP,
  563.     short                 numNewTileMapRows,
  564.     short                numNewTileMapCols)
  565. {
  566.     TileMapStruct        tempTileMapStruct;
  567.     TileMapStructPtr    newTileMapStructP;
  568.     short                row, numRowsToCopy, numColsToCopy;
  569.     Size                arraySize;
  570.     OSErr                err = noErr;
  571.     
  572.     SW_ASSERT(numNewTileMapRows > 0 && numNewTileMapCols > 0);
  573.     
  574.     if (oldTileMapStructP == NULL)
  575.         err = kNullTileMapErr;
  576.     
  577.     
  578.     if (err == noErr)
  579.     {
  580.             // Don't do anything if the TileMap is already the requested size.
  581.         if (oldTileMapStructP->numRows == numNewTileMapRows && 
  582.             oldTileMapStructP->numCols == numNewTileMapCols)
  583.         {
  584.             return noErr;
  585.         }
  586.         
  587.             // Create the new TileMap
  588.         err = SWCreateTileMap(&newTileMapStructP, numNewTileMapRows, numNewTileMapCols);
  589.     }
  590.     
  591.     if (err == noErr)
  592.     {
  593.         if (oldTileMapStructP->isLocked == false)
  594.             SWLockTileMap(oldTileMapStructP);
  595.         
  596.         numRowsToCopy = SW_MIN(oldTileMapStructP->numRows, numNewTileMapRows);
  597.         numColsToCopy = SW_MIN(oldTileMapStructP->numCols, numNewTileMapCols);
  598.         
  599.             // Copy the data from the old TileMap to the new TileMap
  600.         arraySize = (Size)numColsToCopy * sizeof(short);
  601.         for (row = 0; row < numRowsToCopy; row++)
  602.         {
  603.             BlockMoveData(&oldTileMapStructP->tileMap[row][0],
  604.                 &newTileMapStructP->tileMap[row][0], arraySize);
  605.         }
  606.         
  607.             // Swap contents of the new and old TileMapStructs
  608.         tempTileMapStruct = *oldTileMapStructP;
  609.         *oldTileMapStructP = *newTileMapStructP;
  610.         *newTileMapStructP = tempTileMapStruct;
  611.         
  612.             // Dispose the newTileMapStruct, which now contains the old TileMap
  613.         SWDisposeTileMap(&newTileMapStructP);
  614.     }
  615.     
  616.     
  617.     SWSetStickyIfError(err);
  618.     return err;
  619. }
  620.  
  621.  
  622. #pragma mark -
  623. ///--------------------------------------------------------------------------------------
  624. //    SWLoadTileFromCicnResource
  625. ///--------------------------------------------------------------------------------------
  626.  
  627. SW_FUNC OSErr SWLoadTileFromCicnResource(
  628.     SpriteWorldPtr    spriteWorldP, 
  629.     short            tileID,
  630.     short            cicnID, 
  631.     MaskType        maskType,
  632.     Boolean            maskIsPartialMask)
  633. {
  634.     OSErr             err;
  635.     GWorldPtr         saveGWorld;
  636.     GDHandle         saveGDH;
  637.     FramePtr         newFrameP;
  638.     CIconHandle     cIconH;
  639.     Rect            frameRect;
  640.     Boolean            maskIsSolid = false;
  641.     
  642.     SW_ASSERT(spriteWorldP != NULL);
  643.     
  644.     err = noErr;
  645.     newFrameP = NULL;
  646.  
  647.     if ( !spriteWorldP->tilingIsInitialized )
  648.     {
  649.         err = kTilingNotInitialized;
  650.     }
  651.     else if ( tileID < 0 || tileID >= spriteWorldP->maxNumTiles)
  652.     {
  653.         err = kOutOfRangeErr;
  654.     }
  655.     
  656.     if (maskType == kSolidMask)
  657.     {
  658.         maskIsSolid = true;
  659.         maskType = kNoMask;
  660.     }
  661.     
  662.     if ( err == noErr )
  663.     {    
  664.         err = SWCreateFrameFromCicnResource(spriteWorldP, &newFrameP, cicnID, maskType);
  665.         
  666.         if ( err == noErr )
  667.         {    
  668.             newFrameP->tileMaskIsSolid = maskIsSolid;
  669.             
  670.                 // "Fix" the size if the CICN is larger than the tiles are
  671.             if (newFrameP->frameRect.right > spriteWorldP->tileWidth)
  672.                 newFrameP->frameRect.right = spriteWorldP->tileWidth;
  673.             if (newFrameP->frameRect.bottom > spriteWorldP->tileHeight)
  674.                 newFrameP->frameRect.bottom = spriteWorldP->tileHeight;
  675.             
  676.             cIconH = GetCIcon( cicnID );
  677.  
  678.             if (cIconH != NULL)
  679.             {
  680.                 GetGWorld(&saveGWorld, &saveGDH);
  681.                 
  682.                 HLock((Handle)cIconH);
  683.                 frameRect = ((**cIconH).iconPMap.bounds);
  684.                 (**cIconH).iconPMap.baseAddr = *(**cIconH).iconData;
  685.                 (**cIconH).iconBMap.baseAddr = (Ptr)&((**cIconH).iconMaskData ) +
  686.                     ((**cIconH).iconMask.rowBytes * (frameRect.bottom-frameRect.top));    
  687.                                 
  688.                 (void)LockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  689.                 SetGWorld( newFrameP->framePort, NULL );
  690.                 if ( spriteWorldP->pixelDepth > 1 )
  691.                 {
  692.                     CopyBits( (BitMap*)(&((**cIconH).iconPMap)),
  693.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  694.                         &frameRect, &newFrameP->frameRect, srcCopy, nil);
  695.                 }
  696.                 else
  697.                 {
  698.                     CopyBits( (BitMap*)(&((**cIconH).iconBMap)),
  699.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  700.                         &frameRect,
  701.                         &newFrameP->frameRect, srcCopy, nil);
  702.                 }
  703.                     
  704.                     // If this is NOT a partialMask tile and there is a pixelMask, we should  
  705.                     // fix the image again (even though SWCreateFrameFromCicnResource already 
  706.                     // fixed it), since we copied the image over again from the cicn. If it 
  707.                     // is a partialMask tile, we don't fix it, since that would erase the 
  708.                     // non-masked portions of the image, which we need to keep.
  709.                 if ( ((maskType & kPixelMask) != 0) && maskIsPartialMask == false )
  710.                     SWFixImageGWorld( newFrameP->framePort, newFrameP->maskPort, (RectPtr) NULL );
  711.                 
  712.                 UnlockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  713.                 DisposeCIcon( cIconH );
  714.                 SetGWorld( saveGWorld, saveGDH );
  715.             }
  716.             else
  717.             {
  718.                 err = MemError();
  719.             }
  720.         }
  721.         
  722.         if ( err == noErr )
  723.         {
  724.                 // Are we replacing an old tile?
  725.             if (spriteWorldP->tileFrameArray[tileID] != NULL)
  726.             {
  727.                 SWDisposeTile( spriteWorldP, tileID );
  728.             }
  729.             spriteWorldP->tileFrameArray[tileID] = newFrameP;
  730.             newFrameP->useCount++;
  731.         }
  732.     }
  733.     
  734.     if ( err != noErr && newFrameP != NULL )
  735.     {
  736.         SWDisposeFrame(&newFrameP);
  737.     }
  738.     
  739.     SWSetStickyIfError(err);
  740.     return err;
  741. }
  742.  
  743.  
  744. ///--------------------------------------------------------------------------------------
  745. //    SWLoadTilesFromPictResource
  746. ///--------------------------------------------------------------------------------------
  747.  
  748. SW_FUNC OSErr SWLoadTilesFromPictResource(
  749.     SpriteWorldPtr    spriteWorldP, 
  750.     short            startTileID,
  751.     short            endTileID, 
  752.     short            pictResID, 
  753.     short            maskResID,
  754.     MaskType        maskType,
  755.     Boolean            maskIsPartialMask,
  756.     short            horizBorderWidth,
  757.     short            vertBorderHeight)
  758. {
  759.     OSErr             err;
  760.     short            tileIndex;
  761.     FramePtr         newFrameP;
  762.     GWorldPtr        tempPictGWorldP,
  763.                     tempMaskGWorldP,
  764.                     tempTempMaskGWorldP,
  765.                     currentGWorld;
  766.     GDHandle        currentGDH;
  767.     Rect            currentTileRect;
  768.     short            horizOffset,
  769.                     vertOffset;
  770.     Boolean            allTilesDone,
  771.                     maskIsSolid,
  772.                     needToInvertMask;
  773.     
  774.     SW_ASSERT(spriteWorldP != NULL);
  775.     
  776.     err = noErr;
  777.     newFrameP = NULL;
  778.     tempPictGWorldP = NULL;
  779.     tempMaskGWorldP = NULL;
  780.     tempTempMaskGWorldP = NULL;
  781.     maskIsSolid = false;
  782.     needToInvertMask = true;
  783.     
  784.     if ( !spriteWorldP->tilingIsInitialized )
  785.     {
  786.         err = kTilingNotInitialized;
  787.     }
  788.     else if ( startTileID < 0 || endTileID >= spriteWorldP->maxNumTiles)
  789.     {
  790.         err = kOutOfRangeErr;
  791.     }
  792.     
  793.     if (maskType == kSolidMask)
  794.     {
  795.         maskIsSolid = true;
  796.         maskType = kNoMask;
  797.     }
  798.     
  799.     if ( err == noErr )
  800.     {    
  801.             // Create the GWorld that contains the Tiles' images.
  802.         err = SWCreateGWorldFromPictResource( spriteWorldP, &tempPictGWorldP, pictResID );
  803.         
  804.             // Create the GWorld used to hold the mask. 
  805.         if ( err == noErr && maskType != kNoMask )
  806.             err = SWCreateGWorldFromPictResource( spriteWorldP, &tempMaskGWorldP, maskResID );
  807.         
  808.         if (err == noErr)
  809.         {
  810.                 // If this group of tiles are self-masking, create the mask based on the image.
  811.             if ( pictResID == maskResID && tempMaskGWorldP != NULL )
  812.             {
  813.                 err = SWCreatePixelMaskFromGWorld( tempPictGWorldP, tempMaskGWorldP, (RectPtr) NULL );
  814.                 needToInvertMask = false;
  815.                 
  816.                     // If the depth is 8-bits or less, and we need to create a region mask,
  817.                     // invert the maskGWorld so the region mask is created correctly.
  818.                 if (spriteWorldP->pixelDepth <= 8 && (maskType & kRegionMask) != 0 )
  819.                 {
  820.                     SWInvertGWorld(tempMaskGWorldP);
  821.                     needToInvertMask = true;
  822.                 }
  823.             }
  824.             else if ( (maskType & kPixelMask) != 0 )
  825.             {
  826.                     // For Tiles that do NOT have a partialMask (i.e. the mask is whole),
  827.                     // are not self-masking and have a pixel mask, we
  828.                     // should fix the GWorld's image, in case SWTransparentColor
  829.                     // is not white, or in case the depth is 16-bits or above.
  830.                 if (maskIsPartialMask == false)
  831.                     SWFixImageGWorld( tempPictGWorldP, tempMaskGWorldP, (RectPtr) NULL );
  832.             }
  833.         }
  834.         
  835.         if ( err == noErr )
  836.         {
  837.             err = SWCreateFrameFromGWorldAndRectStart( &tempTempMaskGWorldP, 
  838.                     spriteWorldP->tileWidth, spriteWorldP->tileHeight, maskType );
  839.         }
  840.     
  841.         if ( err == noErr )
  842.         {
  843.             SetRect( ¤tTileRect, 0,  0, 
  844.                 spriteWorldP->tileWidth, spriteWorldP->tileHeight );
  845.             tileIndex = startTileID;
  846.             horizOffset = spriteWorldP->tileWidth + horizBorderWidth;
  847.             vertOffset = spriteWorldP->tileHeight + vertBorderHeight;
  848.             
  849.             allTilesDone = false;
  850.             while( !allTilesDone && err == noErr )
  851.             {
  852.                 err = SWCreateFrameFromGWorldAndRectPartial( &newFrameP, tempPictGWorldP, 
  853.                         tempMaskGWorldP, tempTempMaskGWorldP, ¤tTileRect, maskType);
  854.                 
  855.                 if ( newFrameP != NULL && err == noErr )
  856.                 {
  857.                     newFrameP->tileMaskIsSolid = maskIsSolid;
  858.                     
  859.                         // Are we replacing an old tile?
  860.                     if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  861.                     {
  862.                         SWDisposeTile( spriteWorldP, tileIndex );
  863.                     }
  864.                     spriteWorldP->tileFrameArray[tileIndex] = newFrameP;
  865.                     newFrameP->useCount++;
  866.                     
  867.                     tileIndex++;
  868.                     if (tileIndex > endTileID )
  869.                     {
  870.                         allTilesDone = true;
  871.                     }
  872.                     else
  873.                     {
  874.                         if (tileIndex >= spriteWorldP->maxNumTiles)
  875.                         {
  876.                             err = kOutOfRangeErr;
  877.                         }
  878.                         currentTileRect.left += horizOffset;
  879.                         currentTileRect.right += horizOffset;
  880.                         if ( currentTileRect.right > tempPictGWorldP->portRect.right )
  881.                         {
  882.                             currentTileRect.left = 0;
  883.                             currentTileRect.right = spriteWorldP->tileWidth;
  884.                             currentTileRect.top += vertOffset;
  885.                             currentTileRect.bottom += vertOffset;
  886.                             if ( currentTileRect.bottom > tempPictGWorldP->portRect.bottom )
  887.                             {
  888.                                 err = kOutOfRangeErr;
  889.                             }
  890.                         }
  891.                     }
  892.                 }
  893.             }
  894.             
  895.             if (err == noErr)
  896.             {
  897.                     // If a pixel mask is wanted, fix the tempMaskGWorld 
  898.                     // if the depth is 8-bits or less.
  899.                 if ((maskType & kPixelMask) != 0)
  900.                 {
  901.                     if (spriteWorldP->pixelDepth <= 8 && needToInvertMask)
  902.                     {
  903.                         GetGWorld( ¤tGWorld, ¤tGDH );
  904.                         SWInvertGWorld(tempMaskGWorldP);
  905.                         SetGWorld( currentGWorld, currentGDH );
  906.                     }    
  907.                 }        // If no pixel Mask wanted, dispose
  908.                 else    // of the GWorld we used to make region
  909.                 {
  910.                     if (tempMaskGWorldP != NULL)
  911.                     {
  912.                         DisposeGWorld( tempMaskGWorldP );
  913.                         tempMaskGWorldP = NULL;
  914.                     }
  915.                 }
  916.             }
  917.         }
  918.         SWCreateFrameFromGWorldAndRectFinish( tempTempMaskGWorldP );
  919.     }
  920.     
  921.     SWSetStickyIfError(err);
  922.     return err;
  923. }
  924.  
  925.  
  926. ///--------------------------------------------------------------------------------------
  927. //    SWDisposeTile
  928. ///--------------------------------------------------------------------------------------
  929.  
  930. SW_FUNC void SWDisposeTile(
  931.     SpriteWorldPtr    spriteWorldP,
  932.     short            tileID)
  933. {
  934.     short        tileIndex;
  935.     Boolean        gWorldStillInUse;
  936.     
  937.     SW_ASSERT(spriteWorldP != NULL);
  938.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  939.     
  940.         // see if any other tile is using this tile's GWorld
  941.     gWorldStillInUse = false;
  942.     tileIndex = spriteWorldP->maxNumTiles;
  943.     while ( tileIndex-- )
  944.     {
  945.         if ( tileIndex != tileID )
  946.         {
  947.             if ( spriteWorldP->tileFrameArray[tileIndex] != NULL &&
  948.                 ((spriteWorldP->tileFrameArray[tileIndex])->framePort == 
  949.                 (spriteWorldP->tileFrameArray[tileID])->framePort) )
  950.             {
  951.                 gWorldStillInUse = true;
  952.             }
  953.         }
  954.     }
  955.         // set flag that tells SWDisposeFrame whether to dispose of GWorld
  956.     (spriteWorldP->tileFrameArray[tileID])->sharesGWorld = gWorldStillInUse;
  957.     
  958.     (void)SWDisposeFrame( &spriteWorldP->tileFrameArray[tileID] );
  959.     spriteWorldP->tileFrameArray[tileID] = NULL;
  960. }
  961.  
  962.  
  963. ///--------------------------------------------------------------------------------------
  964. //    SWLockTiles
  965. ///--------------------------------------------------------------------------------------
  966.  
  967. SW_FUNC void SWLockTiles(
  968.     SpriteWorldPtr    spriteWorldP)
  969. {
  970.     short        tileIndex;
  971.     
  972.     SW_ASSERT(spriteWorldP != NULL);
  973.     
  974.         // Tiling might not be initialized if this was called from SWLockSpriteWorld
  975.     if (spriteWorldP->tilingIsInitialized)    
  976.     {
  977.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  978.         {
  979.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  980.                 SWLockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  981.         }
  982.     }
  983. }
  984.  
  985.  
  986. ///--------------------------------------------------------------------------------------
  987. //    SWUnlockTiles
  988. ///--------------------------------------------------------------------------------------
  989.  
  990. SW_FUNC void SWUnlockTiles(
  991.     SpriteWorldPtr    spriteWorldP)
  992. {
  993.     short        tileIndex;
  994.     
  995.     SW_ASSERT(spriteWorldP != NULL);
  996.     
  997.         // Tiling might not be initialized if this was called from SWLockSpriteWorld
  998.     if (spriteWorldP->tilingIsInitialized)    
  999.     {
  1000.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  1001.         {
  1002.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  1003.                 SWUnlockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  1004.         }
  1005.     }
  1006. }
  1007.  
  1008.  
  1009. ///--------------------------------------------------------------------------------------
  1010. //    SWCreateExtraBackFrame
  1011. ///--------------------------------------------------------------------------------------
  1012.  
  1013. SW_FUNC OSErr SWCreateExtraBackFrame(
  1014.     SpriteWorldPtr    spriteWorldP,
  1015.     Rect            *frameRect)
  1016. {
  1017.     OSErr    err = noErr;
  1018.     
  1019.     SW_ASSERT(spriteWorldP != NULL);
  1020.     SW_ASSERT(frameRect->right > frameRect->left && frameRect->bottom > frameRect->top);
  1021.     
  1022.     if (spriteWorldP->extraBackFrameP != NULL)
  1023.     {
  1024.         SWDisposeFrame(&spriteWorldP->extraBackFrameP);
  1025.     }
  1026.     
  1027.         // Make sure rect starts at 0,0
  1028.     OffsetRect(frameRect, -frameRect->left, -frameRect->top);
  1029.     
  1030.     err = SWCreateFrame(spriteWorldP->mainSWGDH, &spriteWorldP->extraBackFrameP, 
  1031.             frameRect, spriteWorldP->pixelDepth, kCreateGWorld);
  1032.     
  1033.     return err;
  1034. }
  1035.  
  1036.  
  1037. ///--------------------------------------------------------------------------------------
  1038. //    SWDisposeExtraBackFrame
  1039. ///--------------------------------------------------------------------------------------
  1040.  
  1041. SW_FUNC void SWDisposeExtraBackFrame(
  1042.     SpriteWorldPtr    spriteWorldP)
  1043. {
  1044.     SW_ASSERT(spriteWorldP != NULL);
  1045.     SWDisposeFrame(&spriteWorldP->extraBackFrameP);
  1046.     spriteWorldP->extraBackFrameP = NULL;
  1047. }
  1048.  
  1049.  
  1050. ///--------------------------------------------------------------------------------------
  1051. //    SWSetPortToExtraBackFrame
  1052. ///--------------------------------------------------------------------------------------
  1053.  
  1054. SW_FUNC OSErr SWSetPortToExtraBackFrame(
  1055.     SpriteWorldPtr    spriteWorldP)
  1056. {
  1057.     OSErr    err = noErr;
  1058.     
  1059.     SW_ASSERT(spriteWorldP != NULL);
  1060.     
  1061.     if ( spriteWorldP->extraBackFrameP == NULL )
  1062.         err = kNilFrameErr;
  1063.     else if ( spriteWorldP->extraBackFrameP->isFrameLocked == false)
  1064.         err = kNotLockedErr;
  1065.     
  1066.     if (err == noErr)
  1067.         SetGWorld(spriteWorldP->extraBackFrameP->framePort, nil);
  1068.     
  1069.     SWSetStickyIfError( err );
  1070.     return err;
  1071. }
  1072.  
  1073.  
  1074. ///--------------------------------------------------------------------------------------
  1075. //    SWSetTilingOn
  1076. ///--------------------------------------------------------------------------------------
  1077.  
  1078. SW_FUNC void SWSetTilingOn(
  1079.     SpriteWorldPtr    spriteWorldP,
  1080.     Boolean            tilingIsOn)
  1081. {
  1082.     SW_ASSERT(spriteWorldP != NULL);
  1083.     spriteWorldP->tilingIsOn = tilingIsOn;
  1084. }
  1085.  
  1086.  
  1087. ///--------------------------------------------------------------------------------------
  1088. //    SWChangeTileSize
  1089. ///--------------------------------------------------------------------------------------
  1090.  
  1091. SW_FUNC OSErr SWChangeTileSize(
  1092.     SpriteWorldPtr    spriteWorldP,
  1093.     short             tileHeight,
  1094.     short            tileWidth)
  1095. {
  1096.     OSErr    err;
  1097.     
  1098.     SW_ASSERT(spriteWorldP != NULL);
  1099.     
  1100.     spriteWorldP->tileHeight = tileHeight;
  1101.     spriteWorldP->tileWidth = tileWidth;
  1102.     
  1103.         // Dispose and rebuild the tiling cache, based on the new tile width & height
  1104.     err = SWInitTilingCache(spriteWorldP);
  1105.     
  1106.     return err;
  1107. }
  1108.  
  1109.  
  1110. ///--------------------------------------------------------------------------------------
  1111. //    SWSetSpriteLayerUnderTileLayer
  1112. ///--------------------------------------------------------------------------------------
  1113.  
  1114. SW_FUNC void SWSetSpriteLayerUnderTileLayer(
  1115.     SpriteLayerPtr    spriteLayerP,
  1116.     short            tileLayer)
  1117. {
  1118.     SW_ASSERT(spriteLayerP != NULL);
  1119.     spriteLayerP->tileLayer = tileLayer;
  1120. }
  1121.  
  1122.  
  1123. ///--------------------------------------------------------------------------------------
  1124. //    SWSetTileMaskDrawProc
  1125. ///--------------------------------------------------------------------------------------
  1126.  
  1127. SW_FUNC OSErr SWSetTileMaskDrawProc(
  1128.     SpriteWorldPtr    spriteWorldP,
  1129.     DrawProcPtr        drawProc)
  1130. {
  1131.     OSErr    err = noErr;
  1132.     
  1133.     SW_ASSERT(spriteWorldP != NULL);
  1134.     SW_ASSERT(drawProc != NULL);
  1135.     
  1136. #if SW_PPC
  1137.     if (drawProc == BlitPixieAllBitMaskDrawProc)
  1138.         err = k68kOnlyErr;
  1139. #endif
  1140.     
  1141.     if (drawProc == BlitPixiePartialMaskDrawProc ||
  1142.         drawProc == BlitPixieAllBitPartialMaskDrawProc)
  1143.     {
  1144.         err = kBadParameterErr;
  1145.     }
  1146.     else if (spriteWorldP->pixelDepth < 8)
  1147.     {
  1148.         if (drawProc == BlitPixieMaskDrawProc)
  1149.         {
  1150.             err = kWrongDepthErr;
  1151.         }
  1152.     }
  1153.     
  1154.     if ( err == noErr )
  1155.     {
  1156.         spriteWorldP->tileMaskDrawProc = drawProc;
  1157.     }
  1158.     
  1159.     SWSetStickyIfError( err );
  1160.     return err;
  1161. }
  1162.  
  1163.  
  1164. ///--------------------------------------------------------------------------------------
  1165. //    SWSetPartialMaskDrawProc
  1166. ///--------------------------------------------------------------------------------------
  1167.  
  1168. SW_FUNC OSErr SWSetPartialMaskDrawProc(
  1169.     SpriteWorldPtr    spriteWorldP,
  1170.     DrawProcPtr        drawProc)
  1171. {
  1172.     OSErr    err = noErr;
  1173.     
  1174.     SW_ASSERT(spriteWorldP != NULL);
  1175.     SW_ASSERT(drawProc != NULL);
  1176.     
  1177. #if SW_PPC
  1178.     if (drawProc == BlitPixieAllBitPartialMaskDrawProc)
  1179.         err = k68kOnlyErr;
  1180. #endif
  1181.     
  1182.     if (spriteWorldP->pixelDepth < 8)
  1183.     {
  1184.         if (drawProc == BlitPixiePartialMaskDrawProc)
  1185.         {
  1186.             err = kWrongDepthErr;
  1187.         }
  1188.     }
  1189.  
  1190.     if ( err == noErr )
  1191.     {
  1192.         spriteWorldP->partialMaskDrawProc = drawProc;
  1193.     }
  1194.     
  1195.     SWSetStickyIfError( err );
  1196.     return err;
  1197. }
  1198.  
  1199.  
  1200. ///--------------------------------------------------------------------------------------
  1201. //    SWSetTileChangeProc
  1202. ///--------------------------------------------------------------------------------------
  1203.  
  1204. SW_FUNC void SWSetTileChangeProc(
  1205.     SpriteWorldPtr        spriteWorldP,
  1206.     TileChangeProcPtr    tileChangeProc)
  1207. {
  1208.     SW_ASSERT(spriteWorldP != NULL);
  1209.     spriteWorldP->tileChangeProc = tileChangeProc;
  1210. }
  1211.  
  1212.  
  1213. ///--------------------------------------------------------------------------------------
  1214. //    SWSetTileMaskSolidMode
  1215. ///--------------------------------------------------------------------------------------
  1216.  
  1217. SW_FUNC void SWSetTileMaskSolidMode(
  1218.     SpriteWorldPtr        spriteWorldP,
  1219.     short                tileID,
  1220.     Boolean                isSolid)
  1221. {
  1222.     FramePtr    tileFrameP;
  1223.     
  1224.     SW_ASSERT(tileID >= 0 && tileID < spriteWorldP->maxNumTiles);
  1225.  
  1226.     tileFrameP = spriteWorldP->tileFrameArray[tileID];
  1227.     
  1228.     SW_ASSERT(tileFrameP != NULL);
  1229.     
  1230.     tileFrameP->tileMaskIsSolid = isSolid;
  1231. }
  1232.  
  1233.  
  1234. #pragma mark -
  1235. ///--------------------------------------------------------------------------------------
  1236. //    SWDrawTilesInBackground
  1237. ///--------------------------------------------------------------------------------------
  1238.  
  1239. SW_FUNC OSErr SWDrawTilesInBackground(
  1240.     SpriteWorldPtr    spriteWorldP)
  1241. {
  1242.     GWorldPtr        holdGWorld;
  1243.     GDHandle        holdGDH;
  1244.     OSErr            err = noErr;
  1245.     
  1246.     SW_ASSERT(spriteWorldP != NULL);
  1247.     
  1248.     GetGWorld( &holdGWorld, &holdGDH );
  1249.     
  1250.     if ( !spriteWorldP->tilingIsInitialized )
  1251.         err = kTilingNotInitialized;
  1252.     
  1253.     if (err == noErr)
  1254.     {
  1255.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &spriteWorldP->visScrollRect, true);
  1256.     }
  1257.     
  1258.     SetGWorld( holdGWorld, holdGDH );
  1259.     
  1260.     SWSetStickyIfError(err);
  1261.     return err;
  1262. }
  1263.  
  1264.  
  1265. ///--------------------------------------------------------------------------------------
  1266. //    SWDrawTile - sets value in tileMap and draws tile if visible in visScrollRect.
  1267. //    The main core of this function is very similar to the inner loop of 
  1268. //    SWTileDrawLayersInRect, except that this calls SWAddChangedRect, has code to set the
  1269. //    tiling cache, and makes sure the tile is visible on screen before drawing it.
  1270. //    Oh, and SWDrawTile *sets* the tileID in the tileMap, instead of reading it. :-)
  1271. ///--------------------------------------------------------------------------------------
  1272.  
  1273. SW_FUNC void SWDrawTile(
  1274.     SpriteWorldPtr    spriteWorldP,
  1275.     short            dstTileLayer,
  1276.     short            tileRow,
  1277.     short            tileCol,
  1278.     short            tileID)
  1279. {
  1280.     short        row, col, offscreenTileRow, offscreenTileCol, tileLayer;
  1281.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1282.     Rect*        backRectP = &spriteWorldP->backRect;
  1283.     short        tileHeight = spriteWorldP->tileHeight;
  1284.     short        tileWidth = spriteWorldP->tileWidth;
  1285.     Rect        srcRect, dstRect;
  1286.     FramePtr    tileFrameP;
  1287.     GWorldPtr    saveGWorld;
  1288.     GDHandle    saveGDH;
  1289.     Boolean        tileClipped, tileHasMask;
  1290.     
  1291.         // We must have a TileMap installed in the dstTileLayer to draw in it!
  1292.     if (spriteWorldP->tileLayerArray[dstTileLayer] == NULL)
  1293.         return;
  1294.     
  1295.         // Check SpriteWorldRec
  1296.     SW_ASSERT(spriteWorldP != NULL);
  1297.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  1298.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1299.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1300.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1301.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  1302.     SW_ASSERT(spriteWorldP->tileLayerArray[dstTileLayer] != NULL);
  1303.     SW_ASSERT(spriteWorldP->tileLayerArray[dstTileLayer]->isLocked);
  1304.     
  1305.         // Check parameters
  1306.     SW_ASSERT(dstTileLayer <= spriteWorldP->lastActiveTileLayer);
  1307.     SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[dstTileLayer]->numRows);
  1308.     SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[dstTileLayer]->numCols);
  1309.     SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1310.     
  1311.     GetGWorld( &saveGWorld, &saveGDH );
  1312.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1313.     
  1314.         // Note: we can not return if the tileID is what is already in the TileMap, 
  1315.         // since tile animation would then not work.
  1316.     
  1317.     
  1318.         // Store the new tileID in the TileMap of the dstTileLayer
  1319.     spriteWorldP->tileLayerArray[dstTileLayer]->tileMap[tileRow][tileCol] = tileID;
  1320.     
  1321.     row = tileRow * tileHeight;
  1322.     col = tileCol * tileWidth;
  1323.             
  1324.     dstRect.bottom = row + tileHeight;
  1325.     dstRect.right = col + tileWidth;
  1326.         
  1327.         // Clip tile dstRect with visScrollRect //
  1328.     tileClipped = false;
  1329.     if (row < visScrollRectP->top)
  1330.     {
  1331.         dstRect.top = visScrollRectP->top;
  1332.         tileClipped = true;
  1333.     }
  1334.     else
  1335.         dstRect.top = row;
  1336.     
  1337.     if (col < visScrollRectP->left)
  1338.     {
  1339.         dstRect.left = visScrollRectP->left;
  1340.         tileClipped = true;
  1341.     }
  1342.     else
  1343.         dstRect.left = col;
  1344.     
  1345.     if (dstRect.bottom > visScrollRectP->bottom)
  1346.     {
  1347.         dstRect.bottom = visScrollRectP->bottom;
  1348.         tileClipped = true;
  1349.     }
  1350.     
  1351.     if (dstRect.right > visScrollRectP->right)
  1352.     {
  1353.         dstRect.right = visScrollRectP->right;
  1354.         tileClipped = true;
  1355.     }
  1356.     
  1357.  
  1358.         // Draw tile if visible on screen (in visScrollRect)
  1359.     if (dstRect.left < dstRect.right && dstRect.top < dstRect.bottom)
  1360.     {
  1361.             // Save rect as having been changed
  1362.         SWAddChangedRect(spriteWorldP, &dstRect);
  1363.         
  1364.             // Now get the tileID of this row and col in tileLayer 0
  1365.         if (spriteWorldP->tileLayerArray[0] == NULL)
  1366.             tileID = -1;
  1367.         else
  1368.             tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1369.             
  1370.             // Now we redraw all tiles in this location
  1371.         if (tileID >= 0)
  1372.         {
  1373.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1374.             SW_ASSERT(tileFrameP != NULL);
  1375.             SW_ASSERT(tileFrameP->isFrameLocked);
  1376.             
  1377.                 // Determine whether the tile has a mask with background showing through
  1378.             tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1379.         }
  1380.         else
  1381.             tileHasMask = false;
  1382.         
  1383.             // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1384.             // tile has a mask with background showing through the unmasked part.
  1385.         if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1386.         {
  1387.                 // There is no tile in this spot, or there is a masked tile and
  1388.                 // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1389.                 // Note: the function below wraps the dstRect for us, and leaves it 
  1390.                 // that way when it returns, so we don't have to wrap it ourselves.
  1391.             SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1392.         }
  1393.         else
  1394.         {
  1395.                 // Make the tile's dest rect local to the offscreen area
  1396.             dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1397.             dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1398.             dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1399.             dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1400.             
  1401.                 // Wrap tile to top or bottom of offscreen area
  1402.             if (dstRect.bottom > backRectP->bottom)
  1403.             {
  1404.                 dstRect.top -= backRectP->bottom;
  1405.                 dstRect.bottom -= backRectP->bottom;
  1406.             }
  1407.             else if (dstRect.top < backRectP->top)
  1408.             {
  1409.                 dstRect.top += backRectP->bottom;
  1410.                 dstRect.bottom += backRectP->bottom;
  1411.             }
  1412.             
  1413.                 // Wrap tile to left or right side of offscreen area
  1414.             if (dstRect.right > backRectP->right)
  1415.             {
  1416.                 dstRect.left -= backRectP->right;
  1417.                 dstRect.right -= backRectP->right;
  1418.             }
  1419.             else if (dstRect.left < backRectP->left)
  1420.             {
  1421.                 dstRect.left += backRectP->right;
  1422.                 dstRect.right += backRectP->right;
  1423.             }
  1424.         }
  1425.  
  1426.  
  1427.         if (tileID >= 0)
  1428.         {    
  1429.             srcRect = tileFrameP->frameRect;
  1430.             
  1431.                 // Clip new srcRect
  1432.             if (row < visScrollRectP->top)
  1433.                 srcRect.top += visScrollRectP->top - row;
  1434.             if (col < visScrollRectP->left)
  1435.                 srcRect.left += visScrollRectP->left - col;
  1436.             if (row + tileHeight > visScrollRectP->bottom)
  1437.                 srcRect.bottom -= row + tileHeight - visScrollRectP->bottom;
  1438.             if (col + tileWidth > visScrollRectP->right)
  1439.                 srcRect.right -= col + tileWidth - visScrollRectP->right;
  1440.  
  1441.             if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1442.             {
  1443.                     // The tile has a mask, with background showing through
  1444.                 (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1445.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1446.             }
  1447.             else
  1448.             {
  1449.                     // The entire tile should be drawn
  1450.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1451.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1452.             }
  1453.         }
  1454.         
  1455.         
  1456.             // Draw tiles in higher layers
  1457.         for (tileLayer = 1; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1458.         {
  1459.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1460.                 continue;
  1461.             
  1462.             SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  1463.             SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  1464.             
  1465.             tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  1466.             if (tileID < 0)
  1467.                 continue;
  1468.             
  1469.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1470.             
  1471.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1472.             SW_ASSERT(tileFrameP != NULL);
  1473.             SW_ASSERT(tileFrameP->isFrameLocked);
  1474.             
  1475.             srcRect = tileFrameP->frameRect;
  1476.             
  1477.                 // Clip new srcRect
  1478.             if (row < visScrollRectP->top)
  1479.                 srcRect.top += visScrollRectP->top - row;
  1480.             if (col < visScrollRectP->left)
  1481.                 srcRect.left += visScrollRectP->left - col;
  1482.             if (row + tileHeight > visScrollRectP->bottom)
  1483.                 srcRect.bottom -= row + tileHeight - visScrollRectP->bottom;
  1484.             if (col + tileWidth > visScrollRectP->right)
  1485.                 srcRect.right -= col + tileWidth - visScrollRectP->right;
  1486.             
  1487.                 // Draw the tile
  1488.             if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  1489.             {
  1490.                     // Tile has no mask
  1491.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1492.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1493.             }
  1494.             else
  1495.             {
  1496.                     // Tile has a mask
  1497.                 (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1498.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1499.             }
  1500.         }
  1501.             
  1502.             // Copy tiles from back area to work area
  1503.         SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  1504.         (*spriteWorldP->offscreenDrawProc)(spriteWorldP->backFrameP, 
  1505.                 spriteWorldP->workFrameP, &dstRect, &dstRect);
  1506.         
  1507.             // Update tiling cache info only if only one tile layer is used
  1508.         if (spriteWorldP->lastActiveTileLayer == 0)
  1509.         {
  1510.             offscreenTileRow = dstRect.top / spriteWorldP->tileHeight;
  1511.             offscreenTileCol = dstRect.left / spriteWorldP->tileWidth;
  1512.             
  1513.                 // Set new tile value in tilingCache
  1514.             if (tileClipped || tileID < 0)
  1515.             {
  1516.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1517.             }
  1518.             else
  1519.             {
  1520.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = 
  1521.                     spriteWorldP->curTileImage[tileID];
  1522.             }
  1523.         }
  1524.     }
  1525.     
  1526.         // Restore the port
  1527.     SetGWorld( saveGWorld, saveGDH );
  1528. }
  1529.  
  1530.  
  1531. ///--------------------------------------------------------------------------------------
  1532. //    SWDrawTilesInRect - draw only one layer of tiles in updateRect of backFrame. Note:
  1533. //    The only reason we use this instead of SWDrawTilesLayersInRect is because with this,
  1534. //    we can use the tiling cache.
  1535. ///--------------------------------------------------------------------------------------
  1536.  
  1537. SW_FUNC void SWDrawTilesInRect(
  1538.     SpriteWorldPtr    spriteWorldP,
  1539.     Rect*            updateRectP,
  1540.     Boolean            optimizingOn)
  1541. {
  1542.     short        row, col, tileRow, tileCol, tileID;
  1543.     short        startRow, startCol, stopRow, stopCol;
  1544.     short        offscreenTileRow, offscreenTileCol;
  1545.     Rect        srcRect, dstRect;
  1546.     FramePtr    tileFrameP;
  1547.     Boolean        tileClipped, tileHasMask;
  1548.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1549.     Rect*        backRectP = &spriteWorldP->backRect;
  1550.     Rect        updateRect = *updateRectP;
  1551.     short        tileWidth = spriteWorldP->tileWidth;
  1552.     short        tileHeight = spriteWorldP->tileHeight;
  1553.     
  1554.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1555.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1556.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1557.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1558.     
  1559.     SW_ASSERT(spriteWorldP->tileLayerArray[0] != NULL);
  1560.     SW_ASSERT(spriteWorldP->tileLayerArray[0]->isLocked);
  1561.     SW_ASSERT(tileWidth * spriteWorldP->tileLayerArray[0]->numCols < 32767);
  1562.     SW_ASSERT(tileHeight * spriteWorldP->tileLayerArray[0]->numRows < 32767);
  1563.     
  1564.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1565.     
  1566.         // Convert pixel row and col into tile row and col
  1567.     startRow = updateRect.top / tileHeight;
  1568.     startCol = updateRect.left / tileWidth;
  1569.     stopRow = (updateRect.bottom-1) / tileHeight;
  1570.     stopCol = (updateRect.right-1) / tileWidth;
  1571.  
  1572.  
  1573.     row = startRow * tileHeight;
  1574.     for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1575.     {
  1576.         col = startCol * tileWidth;
  1577.         for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1578.         {
  1579.             if (spriteWorldP->tileLayerArray[0] != NULL)
  1580.             {
  1581.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[0]->numRows);
  1582.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[0]->numCols);
  1583.             }
  1584.                     
  1585.             dstRect.bottom = row + tileHeight;
  1586.             dstRect.right = col + tileWidth;
  1587.             
  1588.                 // Is tile completely visible on screen?
  1589.             if (row >= visScrollRectP->top && col >= visScrollRectP->left &&
  1590.                 dstRect.bottom <= visScrollRectP->bottom && 
  1591.                 dstRect.right <= visScrollRectP->right)
  1592.             {
  1593.                 tileClipped = false;
  1594.             }
  1595.             else
  1596.             {
  1597.                 tileClipped = true;
  1598.             }
  1599.                 
  1600.                 // Clip tile dstRect with updateRect //
  1601.             if (row < updateRect.top)
  1602.                 dstRect.top = updateRect.top;
  1603.             else
  1604.                 dstRect.top = row;
  1605.             
  1606.             if (col < updateRect.left)
  1607.                 dstRect.left = updateRect.left;
  1608.             else
  1609.                 dstRect.left = col;
  1610.             
  1611.             if (dstRect.bottom > updateRect.bottom)
  1612.                 dstRect.bottom = updateRect.bottom;
  1613.             
  1614.             if (dstRect.right > updateRect.right)
  1615.                 dstRect.right = updateRect.right;
  1616.     
  1617.             if (spriteWorldP->tileLayerArray[0] == NULL)
  1618.                 tileID = -1;
  1619.             else
  1620.                 tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1621.             
  1622.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1623.             
  1624.                 
  1625.             if (tileID >= 0)
  1626.             {
  1627.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1628.                 SW_ASSERT(tileFrameP != NULL);
  1629.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1630.                 
  1631.                     // Determine whether the tile has a mask with background showing through
  1632.                 tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1633.             }
  1634.             else
  1635.                 tileHasMask = false;
  1636.             
  1637.                 // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1638.                 // tile has a mask with background showing through the unmasked part.
  1639.             if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1640.             {
  1641.                     // There is no tile in this spot, or there is a masked tile and
  1642.                     // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1643.                     // Note: the function below wraps the dstRect for us, and leaves it 
  1644.                     // that way when it returns, so we don't have to wrap it ourselves.
  1645.                 SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1646.             }
  1647.             else
  1648.             {
  1649.                     // Make the tile's dest rect local to the offscreen area
  1650.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1651.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1652.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1653.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1654.                 
  1655.                     // Wrap tile to top or bottom of offscreen area
  1656.                 if (dstRect.bottom > backRectP->bottom)
  1657.                 {
  1658.                     dstRect.top -= backRectP->bottom;
  1659.                     dstRect.bottom -= backRectP->bottom;
  1660.                 }
  1661.                 else if (dstRect.top < backRectP->top)
  1662.                 {
  1663.                     dstRect.top += backRectP->bottom;
  1664.                     dstRect.bottom += backRectP->bottom;
  1665.                 }
  1666.                 
  1667.                     // Wrap tile to left or right side of offscreen area
  1668.                 if (dstRect.right > backRectP->right)
  1669.                 {
  1670.                     dstRect.left -= backRectP->right;
  1671.                     dstRect.right -= backRectP->right;
  1672.                 }
  1673.                 else if (dstRect.left < backRectP->left)
  1674.                 {
  1675.                     dstRect.left += backRectP->right;
  1676.                     dstRect.right += backRectP->right;
  1677.                 }
  1678.             }
  1679.  
  1680.  
  1681.             offscreenTileRow = dstRect.top / tileHeight;
  1682.             offscreenTileCol = dstRect.left / tileWidth;
  1683.  
  1684.             if (tileID >= 0)
  1685.             {    
  1686.                 srcRect = tileFrameP->frameRect;
  1687.                 
  1688.                     // Clip new srcRect
  1689.                 if (row < updateRect.top)
  1690.                     srcRect.top += updateRect.top - row;
  1691.                 if (col < updateRect.left)
  1692.                     srcRect.left += updateRect.left - col;
  1693.                 if (row + tileHeight > updateRect.bottom)
  1694.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1695.                 if (col + tileWidth > updateRect.right)
  1696.                     srcRect.right -= col + tileWidth - updateRect.right;
  1697.  
  1698.                 if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1699.                 {
  1700.                         // The tile has a mask, with background showing through
  1701.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1702.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1703.                     
  1704.                         // Since the background is showing here, set this cache spot to -1
  1705.                     spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1706.                 }
  1707.                 else
  1708.                 {
  1709.                         // Save time by not drawing tile if already the same
  1710.                     if (spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] != 
  1711.                         spriteWorldP->curTileImage[tileID] || !optimizingOn)
  1712.                     {    
  1713.                             // The entire tile should be drawn
  1714.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1715.                                 spriteWorldP->backFrameP, &srcRect, &dstRect);
  1716.                         
  1717.                             // Set new tile value in tilingCache
  1718.                         if (tileClipped)
  1719.                         {
  1720.                             spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1721.                         }
  1722.                         else
  1723.                         {
  1724.                             spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = 
  1725.                                 spriteWorldP->curTileImage[tileID];
  1726.                         }
  1727.                     }
  1728.                 }
  1729.             }
  1730.             else
  1731.             {
  1732.                     // Since no tile is here, this spot in the tiling Cache should be set to -1
  1733.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1734.                 
  1735.                     // Cause assertion failure if tileID is < 0 and there is no extraBackFrameP
  1736.                 SW_ASSERT(spriteWorldP->extraBackFrameP != NULL);
  1737.             }
  1738.         }
  1739.     }
  1740. }
  1741.  
  1742.  
  1743. ///--------------------------------------------------------------------------------------
  1744. //    SWDrawTileLayersInRect - draws all tile layers in updateRect of backFrame
  1745. ///--------------------------------------------------------------------------------------
  1746.  
  1747. SW_FUNC void SWDrawTileLayersInRect(
  1748.     SpriteWorldPtr    spriteWorldP,
  1749.     Rect*            updateRectP,
  1750.     Boolean            optimizingOn)
  1751. {
  1752.     #pragma        unused(optimizingOn)    // This is used in our sister function, SWDrawTilesInRect
  1753.     short        row, col, tileRow, tileCol, tileID;
  1754.     short        startRow, startCol, stopRow, stopCol;
  1755.     short        tileLayer, startPixelCol;
  1756.     Rect        srcRect, dstRect;
  1757.     FramePtr    tileFrameP;
  1758.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1759.     Rect*        backRectP = &spriteWorldP->backRect;
  1760.     Rect        updateRect = *updateRectP;
  1761.     short        tileWidth = spriteWorldP->tileWidth;
  1762.     short        tileHeight = spriteWorldP->tileHeight;
  1763.     Boolean        tileHasMask;
  1764.     
  1765.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1766.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1767.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1768.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1769.     
  1770.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1771.     
  1772.         // Convert pixel row and col into tile row and col
  1773.     startRow = updateRect.top / tileHeight;
  1774.     startCol = updateRect.left / tileWidth;
  1775.     stopRow = (updateRect.bottom-1) / tileHeight;
  1776.     stopCol = (updateRect.right-1) / tileWidth;
  1777.     
  1778.     startPixelCol = startCol * tileWidth;
  1779.     
  1780.     row = startRow * tileHeight;
  1781.     for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1782.     {
  1783.         col = startPixelCol;
  1784.         for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1785.         {
  1786.             if (spriteWorldP->tileLayerArray[0] != NULL)
  1787.             {
  1788.                 SW_ASSERT(spriteWorldP->tileLayerArray[0]->isLocked);
  1789.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[0]->numRows);
  1790.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[0]->numCols);
  1791.             }
  1792.             
  1793.             dstRect.bottom = row + tileHeight;
  1794.             dstRect.right = col + tileWidth;
  1795.                 
  1796.                 // Clip tile dstRect with updateRect //
  1797.             if (row < updateRect.top)
  1798.                 dstRect.top = updateRect.top;
  1799.             else
  1800.                 dstRect.top = row;
  1801.             
  1802.             if (col < updateRect.left)
  1803.                 dstRect.left = updateRect.left;
  1804.             else
  1805.                 dstRect.left = col;
  1806.             
  1807.             if (dstRect.bottom > updateRect.bottom)
  1808.                 dstRect.bottom = updateRect.bottom;
  1809.             
  1810.             if (dstRect.right > updateRect.right)
  1811.                 dstRect.right = updateRect.right;
  1812.             
  1813.             if (spriteWorldP->tileLayerArray[0] == NULL)
  1814.                 tileID = -1;
  1815.             else
  1816.                 tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1817.             
  1818.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1819.                 
  1820.             if (tileID >= 0)
  1821.             {
  1822.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1823.                 SW_ASSERT(tileFrameP != NULL);
  1824.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1825.                 
  1826.                     // Determine whether the tile has a mask with background showing through
  1827.                 tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1828.             }
  1829.             else
  1830.                 tileHasMask = false;
  1831.             
  1832.                 // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1833.                 // tile has a mask with background showing through the unmasked part.
  1834.             if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1835.             {
  1836.                     // There is no tile in this spot, or there is a masked tile and
  1837.                     // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1838.                     // Note: the function below wraps the dstRect for us, and leaves it 
  1839.                     // that way when it returns, so we don't have to wrap it ourselves.
  1840.                 SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1841.             }
  1842.             else
  1843.             {
  1844.                     // Make the tile's dest rect local to the offscreen area
  1845.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1846.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1847.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1848.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1849.                 
  1850.                     // Wrap tile to top or bottom of offscreen area
  1851.                 if (dstRect.bottom > backRectP->bottom)
  1852.                 {
  1853.                     dstRect.top -= backRectP->bottom;
  1854.                     dstRect.bottom -= backRectP->bottom;
  1855.                 }
  1856.                 else if (dstRect.top < backRectP->top)
  1857.                 {
  1858.                     dstRect.top += backRectP->bottom;
  1859.                     dstRect.bottom += backRectP->bottom;
  1860.                 }
  1861.                 
  1862.                     // Wrap tile to left or right side of offscreen area
  1863.                 if (dstRect.right > backRectP->right)
  1864.                 {
  1865.                     dstRect.left -= backRectP->right;
  1866.                     dstRect.right -= backRectP->right;
  1867.                 }
  1868.                 else if (dstRect.left < backRectP->left)
  1869.                 {
  1870.                     dstRect.left += backRectP->right;
  1871.                     dstRect.right += backRectP->right;
  1872.                 }
  1873.             }
  1874.  
  1875.  
  1876.             if (tileID >= 0)
  1877.             {    
  1878.                 srcRect = tileFrameP->frameRect;
  1879.                 
  1880.                     // Clip new srcRect
  1881.                 if (row < updateRect.top)
  1882.                     srcRect.top += updateRect.top - row;
  1883.                 if (col < updateRect.left)
  1884.                     srcRect.left += updateRect.left - col;
  1885.                 if (row + tileHeight > updateRect.bottom)
  1886.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1887.                 if (col + tileWidth > updateRect.right)
  1888.                     srcRect.right -= col + tileWidth - updateRect.right;
  1889.  
  1890.                 if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1891.                 {
  1892.                         // The tile has a mask, with background showing through
  1893.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1894.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1895.                 }
  1896.                 else
  1897.                 {
  1898.                         // The entire tile should be drawn
  1899.                     (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1900.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1901.                 }
  1902.             }
  1903.             
  1904.             
  1905.                 // Draw tiles in higher layers
  1906.             for (tileLayer = 1; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1907.             {
  1908.                 if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1909.                     continue;
  1910.                 
  1911.                 SW_ASSERT(spriteWorldP->tileLayerArray[tileLayer]->isLocked);
  1912.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  1913.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  1914.                 
  1915.                 tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  1916.                 if (tileID < 0)
  1917.                     continue;
  1918.                 
  1919.                 SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1920.                 
  1921.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1922.                 SW_ASSERT(tileFrameP != NULL);
  1923.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1924.                 
  1925.                 srcRect = tileFrameP->frameRect;
  1926.                 
  1927.                     // Clip new srcRect
  1928.                 if (row < updateRect.top)
  1929.                     srcRect.top += updateRect.top - row;
  1930.                 if (col < updateRect.left)
  1931.                     srcRect.left += updateRect.left - col;
  1932.                 if (row + tileHeight > updateRect.bottom)
  1933.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1934.                 if (col + tileWidth > updateRect.right)
  1935.                     srcRect.right -= col + tileWidth - updateRect.right;
  1936.                 
  1937.                     // Draw the tile
  1938.                 if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  1939.                 {
  1940.                         // Tile has no mask
  1941.                     (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1942.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1943.                 }
  1944.                 else
  1945.                 {
  1946.                         // Tile has a mask
  1947.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1948.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1949.                 }
  1950.             }
  1951.         }
  1952.     }
  1953. }
  1954.  
  1955.  
  1956. ///--------------------------------------------------------------------------------------
  1957. //    SWDrawTilesAboveSprite - draw tiles over sprite using the tiles' masks.
  1958. //    Assumes that updateRect fits within the bounds of the tileMap.
  1959. ///--------------------------------------------------------------------------------------
  1960.  
  1961. SW_FUNC void SWDrawTilesAboveSprite(
  1962.     SpriteWorldPtr    spriteWorldP,
  1963.     Rect*            updateRectP,
  1964.     short            startLayer)
  1965. {
  1966.     Rect*        backRectP = &spriteWorldP->backRect;
  1967.     Rect        updateRect = *updateRectP;
  1968.     short        tileLayer;
  1969.     short        tileWidth = spriteWorldP->tileWidth;
  1970.     short        tileHeight = spriteWorldP->tileHeight;
  1971.     short        row, col, tileRow, tileCol, tileID;
  1972.     short        startRow, startCol, stopRow, stopCol;
  1973.     short        startPixelRow, startPixelCol;
  1974.     Rect        srcRect, dstRect;
  1975.     FramePtr    tileFrameP;
  1976.  
  1977.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1978.     SW_ASSERT(startLayer >= 0);
  1979.     
  1980.         // Convert pixel row and col into tile row and col
  1981.     startRow = updateRect.top / tileHeight;
  1982.     startCol = updateRect.left / tileWidth;
  1983.     stopRow = (updateRect.bottom-1) / tileHeight;
  1984.     stopCol = (updateRect.right-1) / tileWidth;
  1985.     
  1986.     startPixelRow = startRow * tileHeight;
  1987.     startPixelCol = startCol * tileWidth;
  1988.  
  1989.     for (tileLayer = startLayer; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1990.     {
  1991.         if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1992.             continue;
  1993.         
  1994.         row = startPixelRow;
  1995.         for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1996.         {
  1997.             col = startPixelCol;
  1998.             for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1999.             {
  2000.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  2001.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  2002.     
  2003.                 tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  2004.                 if (tileID < 0)
  2005.                     continue;
  2006.                 
  2007.                 SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  2008.                 
  2009.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  2010.                 SW_ASSERT(tileFrameP != NULL);
  2011.                 
  2012.                     // Skip tiles in the bottom layer that have no mask, and therefore 
  2013.                     // aren't above the sprites, as long as no extraBackFrameP is installed.
  2014.                 if (tileLayer == 0 && spriteWorldP->extraBackFrameP == NULL &&
  2015.                     tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL && 
  2016.                     tileFrameP->tileMaskIsSolid == false)
  2017.                 {
  2018.                     continue;
  2019.                 }
  2020.                 
  2021.                 srcRect = tileFrameP->frameRect;
  2022.                 dstRect.bottom = row + tileHeight;
  2023.                 dstRect.right = col + tileWidth;
  2024.                 
  2025.                     
  2026.                     // Clip tile dstRect with updateRect //
  2027.                 if (row < updateRect.top)
  2028.                 {
  2029.                     dstRect.top = updateRect.top;
  2030.                     srcRect.top += updateRect.top - row;
  2031.                 }
  2032.                 else
  2033.                     dstRect.top = row;
  2034.                 
  2035.                 if (col < updateRect.left)
  2036.                 {
  2037.                     dstRect.left = updateRect.left;
  2038.                     srcRect.left += updateRect.left - col;
  2039.                 }
  2040.                 else
  2041.                     dstRect.left = col;
  2042.                 
  2043.                 
  2044.                 if (dstRect.bottom > updateRect.bottom)
  2045.                 {
  2046.                     srcRect.bottom -= dstRect.bottom - updateRect.bottom;
  2047.                     dstRect.bottom = updateRect.bottom;
  2048.                 }
  2049.                 
  2050.                 if (dstRect.right > updateRect.right)
  2051.                 {
  2052.                     srcRect.right -= dstRect.right - updateRect.right;
  2053.                     dstRect.right = updateRect.right;
  2054.                 }
  2055.         
  2056.     
  2057.                 
  2058.                     // Make the tile's dest rect local to the offscreen area
  2059.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  2060.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  2061.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  2062.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  2063.                 
  2064.                     // Wrap tile to top or bottom of offscreen area
  2065.                 if (dstRect.bottom > backRectP->bottom)
  2066.                 {
  2067.                     dstRect.top -= backRectP->bottom;
  2068.                     dstRect.bottom -= backRectP->bottom;
  2069.                 }
  2070.                 else if (dstRect.top < backRectP->top)
  2071.                 {
  2072.                     dstRect.top += backRectP->bottom;
  2073.                     dstRect.bottom += backRectP->bottom;
  2074.                 }
  2075.                 
  2076.                     // Wrap tile to left or right side of offscreen area
  2077.                 if (dstRect.right > backRectP->right)
  2078.                 {
  2079.                     dstRect.left -= backRectP->right;
  2080.                     dstRect.right -= backRectP->right;
  2081.                 }
  2082.                 else if (dstRect.left < backRectP->left)
  2083.                 {
  2084.                     dstRect.left += backRectP->right;
  2085.                     dstRect.right += backRectP->right;
  2086.                 }
  2087.                 
  2088.                 if (tileLayer == 0 && spriteWorldP->extraBackFrameP == NULL)
  2089.                 {
  2090.                         // The tile is in the bottom layer
  2091.                     if (tileFrameP->tileMaskIsSolid)
  2092.                     {
  2093.                             // Draw the tile without using a mask
  2094.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  2095.                             spriteWorldP->workFrameP, &srcRect, &dstRect);
  2096.                     }
  2097.                     else
  2098.                     {
  2099.                             // Draw the masked part of the tile
  2100.                         (*spriteWorldP->partialMaskDrawProc)(tileFrameP, 
  2101.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2102.                     }
  2103.                 }
  2104.                 else
  2105.                 {
  2106.                         // The tile is in a higher layer, or is in the background layer and
  2107.                         // an extraBackFrameP is installed, and must be handled differently
  2108.                     if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  2109.                     {
  2110.                             // Tile has no mask
  2111.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  2112.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2113.                     }
  2114.                     else
  2115.                     {
  2116.                             // Tile has a mask
  2117.                         (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  2118.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2119.                     }
  2120.                 }
  2121.             }
  2122.         }
  2123.     }
  2124. }
  2125.  
  2126.  
  2127. ///--------------------------------------------------------------------------------------
  2128. //    SWResetTilingCache
  2129. ///--------------------------------------------------------------------------------------
  2130.  
  2131. SW_FUNC void SWResetTilingCache(
  2132.     SpriteWorldPtr    spriteWorldP)
  2133. {
  2134.     short    row, col;
  2135.     
  2136.     SW_ASSERT(spriteWorldP != NULL);
  2137.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  2138.     
  2139.         // Set all elements to -1 (indicating that each tile needs to be drawn)
  2140.     for (row = 0; row < spriteWorldP->numTilingCacheRows; row++)
  2141.     {
  2142.         for (col = 0; col < spriteWorldP->numTilingCacheCols; col++)
  2143.         {
  2144.             spriteWorldP->tilingCache[row][col] = -1;
  2145.         }
  2146.     }
  2147. }
  2148.  
  2149.  
  2150. ///--------------------------------------------------------------------------------------
  2151. //    SWAddChangedRect - used by SWDrawTile
  2152. ///--------------------------------------------------------------------------------------
  2153.  
  2154. SW_FUNC void SWAddChangedRect(
  2155.     SpriteWorldPtr    spriteWorldP, 
  2156.     Rect            *changedRectP)
  2157. {
  2158.     short    index;
  2159.     Rect    *changedTileP;
  2160.     
  2161.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2162.     SW_ASSERT(changedRectP->top >= 0 && changedRectP->left >= 0 &&
  2163.         changedRectP->right > changedRectP->left && changedRectP->bottom > changedRectP->top);
  2164.     
  2165.     changedTileP = spriteWorldP->changedTiles;
  2166.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++ )
  2167.     {
  2168.             // check for changedRectP entirely contained by changedTileP
  2169.         if ( changedTileP->left <= changedRectP->left && 
  2170.              changedTileP->top <= changedRectP->top && 
  2171.              changedTileP->right >= changedRectP->right && 
  2172.              changedTileP->bottom >= changedRectP->bottom ) 
  2173.         {
  2174.             return;
  2175.         }
  2176.     }
  2177.     
  2178.     changedTileP = spriteWorldP->changedTiles;
  2179.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++ )
  2180.     {
  2181.             // check for changedRectP horizontally adjacent to changedTileP
  2182.         if ( changedTileP->top == changedRectP->top && 
  2183.              changedTileP->bottom == changedRectP->bottom )
  2184.         {
  2185.             if ( changedRectP->left <= changedTileP->left &&         // changedRectP is to the left of changedTileP
  2186.                  changedRectP->right >= changedTileP->left ||        // or
  2187.                  changedRectP->left <= changedTileP->right &&         // changedRectP is to the right of changedTileP
  2188.                  changedRectP->right >= changedTileP->right )
  2189.             {
  2190.                 changedTileP->left = SW_MIN( changedTileP->left, changedRectP->left );
  2191.                 changedTileP->right = SW_MAX( changedTileP->right, changedRectP->right );
  2192.                 return;
  2193.             }
  2194.         }
  2195.         
  2196.             // check for changedRectP vertically adjacent to changedTileP
  2197.         if ( changedTileP->left == changedRectP->left && 
  2198.              changedTileP->right == changedRectP->right )
  2199.         {
  2200.             if ( changedRectP->top <= changedTileP->top &&             // changedRectP is above changedTileP
  2201.                  changedRectP->bottom >= changedTileP->top ||        // or
  2202.                  changedRectP->top <= changedTileP->bottom &&         // changedRectP is below changedTileP
  2203.                  changedRectP->bottom >= changedTileP->bottom )
  2204.             {
  2205.                 changedTileP->top = SW_MIN( changedTileP->top, changedRectP->top );
  2206.                 changedTileP->bottom = SW_MAX( changedTileP->bottom, changedRectP->bottom );
  2207.                 return;
  2208.             }
  2209.         }
  2210.     }
  2211.     
  2212.     if (spriteWorldP->numTilesChanged < spriteWorldP->changedTilesArraySize)
  2213.     {
  2214.         spriteWorldP->changedTiles[spriteWorldP->numTilesChanged++] = *changedRectP;
  2215.     }
  2216.     else
  2217.     {
  2218.             // This shouldn't ever happen, but if it does, we'll trip our Assert routine.
  2219.         SW_ASSERT(0);
  2220.         SWFlagRectAsChanged(spriteWorldP, changedRectP);
  2221.     }
  2222. }
  2223.  
  2224.  
  2225. ///--------------------------------------------------------------------------------------
  2226. //    SWChangeTileImage
  2227. ///--------------------------------------------------------------------------------------
  2228.  
  2229. SW_FUNC void SWChangeTileImage(
  2230.     SpriteWorldPtr    spriteWorldP,
  2231.     short            tileID,
  2232.     short            newImage)
  2233. {
  2234.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2235.     SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  2236.     SW_ASSERT(newImage < spriteWorldP->maxNumTiles);
  2237.     
  2238.         // Set the current image
  2239.     spriteWorldP->curTileImage[tileID] = newImage;
  2240.     
  2241.         // Update the tile image on screen
  2242.     SWUpdateTileOnScreen(spriteWorldP, tileID);
  2243. }
  2244.  
  2245.  
  2246. ///--------------------------------------------------------------------------------------
  2247. //    SWUpdateTileOnScreen - render new tile image in offscreen areas
  2248. ///--------------------------------------------------------------------------------------
  2249.  
  2250. SW_FUNC void SWUpdateTileOnScreen(
  2251.     SpriteWorldPtr    spriteWorldP,
  2252.     short            tileID)
  2253. {
  2254.     short        tileRow, tileCol, tileLayer;
  2255.     short        startRow, startCol, stopRow, stopCol;
  2256.     
  2257.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2258.     
  2259.         // Convert pixel row and col into tile row and col
  2260.     startRow = spriteWorldP->visScrollRect.top / spriteWorldP->tileHeight;
  2261.     startCol = spriteWorldP->visScrollRect.left / spriteWorldP->tileWidth;
  2262.     stopRow = (spriteWorldP->visScrollRect.bottom-1) / spriteWorldP->tileHeight;
  2263.     stopCol = (spriteWorldP->visScrollRect.right-1) / spriteWorldP->tileWidth;
  2264.     
  2265.     for (tileLayer = 0; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  2266.     {
  2267.         if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2268.             continue;
  2269.         
  2270.         for (tileRow = startRow; tileRow <= stopRow; tileRow++)
  2271.         {
  2272.             for (tileCol = startCol; tileCol <= stopCol; tileCol++)
  2273.             {
  2274.                 if (tileID == spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol])
  2275.                     SWDrawTile(spriteWorldP, tileLayer, tileRow, tileCol, tileID);
  2276.             }
  2277.         }
  2278.     }
  2279. }
  2280.  
  2281.  
  2282. ///--------------------------------------------------------------------------------------
  2283. //    SWResetCurrentTileImages
  2284. ///--------------------------------------------------------------------------------------
  2285.  
  2286. SW_FUNC void SWResetCurrentTileImages(
  2287.     SpriteWorldPtr    spriteWorldP)
  2288. {
  2289.     short    tileIndex;
  2290.     
  2291.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2292.     
  2293.     if (spriteWorldP->tilingIsInitialized)
  2294.     {
  2295.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  2296.             spriteWorldP->curTileImage[tileIndex] = tileIndex;
  2297.     }
  2298. }
  2299.  
  2300.  
  2301. ///--------------------------------------------------------------------------------------
  2302. //   SWReturnTileUnderPixel
  2303. ///--------------------------------------------------------------------------------------
  2304.  
  2305. SW_FUNC short SWReturnTileUnderPixel(
  2306.     SpriteWorldPtr    spriteWorldP,
  2307.     short    tileLayer,
  2308.     short    pixelCol,
  2309.     short    pixelRow)
  2310. {
  2311.     short     row, col;
  2312.     
  2313.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2314.     SW_ASSERT(tileLayer < kNumTileLayers);
  2315.     
  2316.     if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2317.         return -1;    // No tile here, since there is no tileMap!
  2318.     
  2319.     row = pixelRow / spriteWorldP->tileHeight;
  2320.     col = pixelCol / spriteWorldP->tileWidth;
  2321.     
  2322.     if (row < 0 || row >= spriteWorldP->tileLayerArray[tileLayer]->numRows ||
  2323.         col < 0 || col >= spriteWorldP->tileLayerArray[tileLayer]->numCols )
  2324.     {
  2325.         return -1;    // Pixel location is outside TileMap bounds!
  2326.     }
  2327.     else
  2328.     {
  2329.         return spriteWorldP->tileLayerArray[tileLayer]->tileMap[row][col];
  2330.     }
  2331. }
  2332.  
  2333.  
  2334. ///--------------------------------------------------------------------------------------
  2335. //   SWCheckSpriteWithTiles
  2336. ///--------------------------------------------------------------------------------------
  2337.  
  2338. SW_FUNC Boolean SWCheckSpriteWithTiles(
  2339.     SpriteWorldPtr    spriteWorldP,
  2340.     SpritePtr        srcSpriteP, 
  2341.     SWTileSearchType searchType,
  2342.     Rect            *insetRectP,
  2343.     short            startTileLayer,
  2344.     short            endTileLayer,
  2345.     short            firstTileID,
  2346.     short            lastTileID,
  2347.     Boolean            fixPosition)
  2348. {
  2349.     short             row, col, startRow, stopRow, startCol, stopCol;
  2350.     TileMapPtr        tileMap;
  2351.     Rect            oldFrameRect, destFrameRect;
  2352.     Boolean            foundTile = false;
  2353.     Boolean            rowLoopTest, colLoopTest;
  2354.     short            temp, tileID, tileLayer, rowIncrement, colIncrement;
  2355.     
  2356.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2357.     SW_ASSERT(startTileLayer >= 0 && endTileLayer < kNumTileLayers);
  2358.     SW_ASSERT(srcSpriteP != NULL);
  2359.     
  2360.     oldFrameRect = srcSpriteP->oldFrameRect;
  2361.     destFrameRect = srcSpriteP->destFrameRect;
  2362.     
  2363.     if (insetRectP != NULL)
  2364.     {
  2365.         oldFrameRect.left += insetRectP->left;
  2366.         oldFrameRect.top += insetRectP->top;
  2367.         oldFrameRect.right -= insetRectP->right;
  2368.         oldFrameRect.bottom -= insetRectP->bottom;
  2369.         
  2370.         destFrameRect.left += insetRectP->left;
  2371.         destFrameRect.top += insetRectP->top;
  2372.         destFrameRect.right -= insetRectP->right;
  2373.         destFrameRect.bottom -= insetRectP->bottom;
  2374.     }
  2375.     
  2376.         // We must do this so sprites hanging off the top or left side of the TileMap
  2377.         // are still handled correctly. (The conversion from pixel to row won't work
  2378.         // correctly for negative numbers, so we "fix" the problem here.)
  2379.     if (oldFrameRect.top < 0)
  2380.         oldFrameRect.top -= spriteWorldP->tileHeight;
  2381.     if (oldFrameRect.bottom <= 0)    
  2382.         oldFrameRect.bottom -= spriteWorldP->tileHeight;
  2383.     
  2384.     if (oldFrameRect.left <= 0)
  2385.         oldFrameRect.left -= spriteWorldP->tileWidth;
  2386.     if (oldFrameRect.right <= 0)
  2387.         oldFrameRect.right -= spriteWorldP->tileWidth;
  2388.     
  2389.     if (destFrameRect.left < 0)
  2390.         destFrameRect.left -= spriteWorldP->tileWidth;
  2391.     if (destFrameRect.right <= 0)    
  2392.         destFrameRect.right -= spriteWorldP->tileWidth;
  2393.     
  2394.     if (destFrameRect.top < 0)
  2395.         destFrameRect.top -= spriteWorldP->tileHeight;
  2396.     if (destFrameRect.bottom <= 0)    
  2397.         destFrameRect.bottom -= spriteWorldP->tileHeight;
  2398.         
  2399.     
  2400.         // startRow = the tile the oldFrameRect.side was about to run into.
  2401.         // stopRow = the tile the destFrameRect.side is currently in.
  2402.         // Function returns early if the sprite didn't move over
  2403.         // a tile's bounds since last frame.
  2404.  
  2405.     if (searchType == kSWTopSide)
  2406.     {
  2407.         startRow = (oldFrameRect.top / spriteWorldP->tileHeight);
  2408.         stopRow = destFrameRect.top / spriteWorldP->tileHeight;
  2409.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2410.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2411.         if (fixPosition)
  2412.             startRow--;        // Check tile just above startRow
  2413.         if (stopRow > startRow)
  2414.             return false;
  2415.     }
  2416.     else if (searchType == kSWBottomSide)
  2417.     {
  2418.         startRow = ((oldFrameRect.bottom-1) / spriteWorldP->tileHeight);
  2419.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2420.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2421.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2422.         if (fixPosition)    // Check tile just below startRow
  2423.             startRow++;    
  2424.         if (stopRow < startRow)
  2425.             return false;
  2426.     }
  2427.     else if (searchType == kSWRightSide)
  2428.     {
  2429.         startCol = ((oldFrameRect.right-1) / spriteWorldP->tileWidth);
  2430.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2431.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2432.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2433.         if (fixPosition)    // Check tile just to the right of startCol
  2434.             startCol++;
  2435.         if (stopCol < startCol)
  2436.             return false;
  2437.     }
  2438.     else if (searchType == kSWLeftSide)
  2439.     {
  2440.         startCol = oldFrameRect.left / spriteWorldP->tileWidth;
  2441.         stopCol = destFrameRect.left / spriteWorldP->tileWidth;
  2442.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2443.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2444.         if (fixPosition)                // Check tile just to the left of startCol
  2445.             startCol--;        
  2446.         if (stopCol > startCol)
  2447.             return false;
  2448.     }
  2449.     else    // searchType == kSWEntireSprite
  2450.     {
  2451.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2452.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2453.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2454.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2455.     }
  2456.     
  2457.     if (startRow <= stopRow)
  2458.         rowIncrement = 1;
  2459.     else
  2460.         rowIncrement = -1;
  2461.     
  2462.     if (startCol <= stopCol)
  2463.         colIncrement = 1;
  2464.     else
  2465.         colIncrement = -1;
  2466.  
  2467.     
  2468.         // Find the first tileLayer that's not NULL
  2469.     for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2470.     {
  2471.         if (spriteWorldP->tileLayerArray[tileLayer] != NULL)
  2472.             break;
  2473.     }
  2474.     
  2475.     
  2476.         // Make sure things are within bounds (in case Sprite is hanging off edge of TileMap)
  2477.     if (rowIncrement > 0)
  2478.     {
  2479.         if (stopRow < 0)
  2480.             return false;
  2481.         else if (stopRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2482.             stopRow = spriteWorldP->tileLayerArray[tileLayer]->numRows-1;
  2483.         
  2484.         if (startRow < 0)
  2485.             startRow = 0;
  2486.         else if (startRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2487.             return false;
  2488.     }
  2489.     else    // rowIncrement < 0
  2490.     {
  2491.         if (startRow < 0)
  2492.             return false;
  2493.         else if (startRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2494.             startRow = spriteWorldP->tileLayerArray[tileLayer]->numRows-1;
  2495.         
  2496.         if (stopRow < 0)
  2497.             stopRow = 0;
  2498.         else if (stopRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2499.             return false;
  2500.     }
  2501.  
  2502.     if (colIncrement > 0)
  2503.     {
  2504.         if (stopCol < 0)
  2505.             return false;
  2506.         else if (stopCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2507.             stopCol = spriteWorldP->tileLayerArray[tileLayer]->numCols-1;
  2508.         
  2509.         if (startCol < 0)
  2510.             startCol = 0;
  2511.         else if (startCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2512.             return false;
  2513.     }
  2514.     else    // colIncrement < 0
  2515.     {
  2516.         if (startCol < 0)
  2517.             return false;
  2518.         else if (startCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2519.             startCol = spriteWorldP->tileLayerArray[tileLayer]->numCols-1;
  2520.         
  2521.         if (stopCol < 0)
  2522.             stopCol = 0;
  2523.         else if (stopCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2524.             return false;
  2525.     }
  2526.  
  2527.     
  2528.     
  2529.         // Look for the tiles in each layer. We have two separate loops: one that scans
  2530.         // through each row, then each col, and one that scans through each col, then each
  2531.         // row. You must use the correct type depending on which direction the sprite is moving.
  2532.         // (horizontally or vertically) for things to work correctly.
  2533.     
  2534.     if (searchType == kSWTopSide || searchType == kSWBottomSide || searchType == kSWEntireSprite)
  2535.     {
  2536.         for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2537.         {
  2538.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2539.                 continue;
  2540.             
  2541.             tileMap = spriteWorldP->tileLayerArray[tileLayer]->tileMap;
  2542.             
  2543.                 // Scan through all cols in a row before moving to next row
  2544.             rowLoopTest = true;
  2545.             for (row = startRow; rowLoopTest; row += rowIncrement)
  2546.             {
  2547.                 rowLoopTest = row != stopRow;
  2548.                 
  2549.                 colLoopTest = true;
  2550.                 for (col = startCol; colLoopTest; col += colIncrement)
  2551.                 {
  2552.                     colLoopTest = col != stopCol;
  2553.                     tileID = tileMap[row][col];
  2554.                     if (tileID >= firstTileID && tileID <= lastTileID)
  2555.                     {
  2556.                         foundTile = true;
  2557.                         goto exit;
  2558.                     }
  2559.                 }
  2560.             }
  2561.         }
  2562.     }
  2563.     else
  2564.     {
  2565.         for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2566.         {
  2567.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2568.                 continue;
  2569.             
  2570.             tileMap = spriteWorldP->tileLayerArray[tileLayer]->tileMap;
  2571.             
  2572.                 // Scan through all rows in a col before moving to next col
  2573.             colLoopTest = true;
  2574.             for (col = startCol; colLoopTest; col += colIncrement)
  2575.             {
  2576.                 colLoopTest = col != stopCol;
  2577.                 
  2578.                 rowLoopTest = true;
  2579.                 for (row = startRow; rowLoopTest; row += rowIncrement)
  2580.                 {
  2581.                     rowLoopTest = row != stopRow;
  2582.                     tileID = tileMap[row][col];
  2583.                     if (tileID >= firstTileID && tileID <= lastTileID)
  2584.                     {
  2585.                         foundTile = true;
  2586.                         goto exit;
  2587.                     }
  2588.                 }
  2589.             }
  2590.         }
  2591.     }
  2592.     
  2593. exit:
  2594.  
  2595.     
  2596.     if (foundTile && fixPosition)
  2597.     {
  2598.         if (searchType == kSWTopSide)
  2599.         {
  2600.                 // (top of tile just below the tile the sprite is in) - (curSpriteTop)
  2601.             temp = (row+1) * spriteWorldP->tileHeight - destFrameRect.top;
  2602.             srcSpriteP->destFrameRect.top += temp;
  2603.             srcSpriteP->destFrameRect.bottom += temp;
  2604.             srcSpriteP->needsToBeDrawn = true;
  2605.         }
  2606.         else if (searchType == kSWBottomSide)
  2607.         {
  2608.             temp = destFrameRect.bottom - row * spriteWorldP->tileHeight;
  2609.             srcSpriteP->destFrameRect.top -= temp;
  2610.             srcSpriteP->destFrameRect.bottom -= temp;
  2611.             srcSpriteP->needsToBeDrawn = true;
  2612.         }
  2613.         else if (searchType == kSWRightSide)
  2614.         {
  2615.             temp = destFrameRect.right - col * spriteWorldP->tileWidth;
  2616.             srcSpriteP->destFrameRect.left -= temp;
  2617.             srcSpriteP->destFrameRect.right -= temp;
  2618.             srcSpriteP->needsToBeDrawn = true;
  2619.         }
  2620.         else if (searchType == kSWLeftSide)
  2621.         {
  2622.             temp = (col+1) * spriteWorldP->tileWidth - destFrameRect.left;
  2623.             srcSpriteP->destFrameRect.left += temp;
  2624.             srcSpriteP->destFrameRect.right += temp;
  2625.             srcSpriteP->needsToBeDrawn = true;
  2626.         }
  2627.     }
  2628.     
  2629.     return foundTile;
  2630. }
  2631.  
  2632.  
  2633. ///--------------------------------------------------------------------------------------
  2634. //    SWWrapRectToWorkArea - I think this is identical to SWEraseWrappedSprite, and is here
  2635. //    simply so Scrolling.c isn't required during compiles.
  2636. ///--------------------------------------------------------------------------------------
  2637.  
  2638. SW_FUNC void SWWrapRectToWorkArea(
  2639.     SpriteWorldPtr    spriteWorldP,
  2640.     Rect*            destRectP)
  2641. {
  2642.     Rect        destRect = *destRectP;
  2643.     Rect        tempDestRect;
  2644.     FramePtr    srcFrameP = spriteWorldP->backFrameP;
  2645.     FramePtr    dstFrameP = spriteWorldP->workFrameP;
  2646.     
  2647.     SW_ASSERT(spriteWorldP != NULL);
  2648.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  2649.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  2650.     
  2651.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  2652.     
  2653.         // Make destRect local to the offscreen area
  2654.     destRect.top -= spriteWorldP->vertScrollRectOffset;
  2655.     destRect.bottom -= spriteWorldP->vertScrollRectOffset;
  2656.     destRect.left -= spriteWorldP->horizScrollRectOffset;
  2657.     destRect.right -= spriteWorldP->horizScrollRectOffset;
  2658.     
  2659.     
  2660.         // Draw main image
  2661.     (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, &destRect, &destRect);
  2662.     
  2663.     
  2664.         // Wrap to top //
  2665.     if (destRect.bottom > dstFrameP->frameRect.bottom)
  2666.     {
  2667.         tempDestRect.top = destRect.top - dstFrameP->frameRect.bottom;
  2668.         tempDestRect.bottom = destRect.bottom - dstFrameP->frameRect.bottom;
  2669.         tempDestRect.left = destRect.left;
  2670.         tempDestRect.right = destRect.right;
  2671.         
  2672.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2673.             &tempDestRect, &tempDestRect);
  2674.         
  2675.             // Wrap to upper left or right corner //
  2676.         if (destRect.right > dstFrameP->frameRect.right)
  2677.         {
  2678.             tempDestRect.left -= dstFrameP->frameRect.right;
  2679.             tempDestRect.right -= dstFrameP->frameRect.right;
  2680.             
  2681.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2682.                 &tempDestRect, &tempDestRect);
  2683.         }
  2684.         else if (destRect.left < dstFrameP->frameRect.left)
  2685.         {
  2686.             tempDestRect.left += dstFrameP->frameRect.right;
  2687.             tempDestRect.right += dstFrameP->frameRect.right;
  2688.             
  2689.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2690.                 &tempDestRect, &tempDestRect);
  2691.         }
  2692.     }
  2693.     
  2694.             // Wrap to left or right side //
  2695.     if (destRect.right > dstFrameP->frameRect.right)
  2696.     {
  2697.         tempDestRect.top = destRect.top;
  2698.         tempDestRect.bottom = destRect.bottom;
  2699.         tempDestRect.left = destRect.left - dstFrameP->frameRect.right;
  2700.         tempDestRect.right = destRect.right - dstFrameP->frameRect.right;
  2701.         
  2702.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2703.             &tempDestRect, &tempDestRect);
  2704.     }
  2705.     else if (destRect.left < dstFrameP->frameRect.left)
  2706.     {
  2707.         tempDestRect.top = destRect.top;
  2708.         tempDestRect.bottom = destRect.bottom;
  2709.         tempDestRect.left = destRect.left + dstFrameP->frameRect.right;
  2710.         tempDestRect.right = destRect.right + dstFrameP->frameRect.right;
  2711.         
  2712.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2713.             &tempDestRect, &tempDestRect);
  2714.     }
  2715.     
  2716.     
  2717.             // Wrap to bottom //
  2718.     if (destRect.top < dstFrameP->frameRect.top)
  2719.     {
  2720.         tempDestRect.top = destRect.top + dstFrameP->frameRect.bottom;
  2721.         tempDestRect.bottom = destRect.bottom + dstFrameP->frameRect.bottom;
  2722.         tempDestRect.left = destRect.left;
  2723.         tempDestRect.right = destRect.right;
  2724.         
  2725.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2726.             &tempDestRect, &tempDestRect);
  2727.         
  2728.             // Wrap to lower left or right corner //
  2729.         if (destRect.right > dstFrameP->frameRect.right)
  2730.         {
  2731.             tempDestRect.left -= dstFrameP->frameRect.right;
  2732.             tempDestRect.right -= dstFrameP->frameRect.right;
  2733.             
  2734.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2735.                 &tempDestRect, &tempDestRect);
  2736.         }
  2737.         else if (destRect.left < dstFrameP->frameRect.left)
  2738.         {
  2739.             tempDestRect.left += dstFrameP->frameRect.right;
  2740.             tempDestRect.right += dstFrameP->frameRect.right;
  2741.             
  2742.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2743.                 &tempDestRect, &tempDestRect);
  2744.         }
  2745.     }
  2746. }
  2747.  
  2748.  
  2749. ///--------------------------------------------------------------------------------------
  2750. //    SWWrapRectFromExtraBackFrame - similar to SWWrapRectToScreen, just modified so the
  2751. //    srcFramePtr is the extraBackFramePtr, the dstFrameP is the backFrameP, and the src
  2752. //    and dst rects are what they should be. Note: the dstRect you pass to this function is
  2753. //    the tile's rect *before* it's made local to the offscreen area and wrapped. It is also
  2754. //    important that the actual dstRectP is modified, not a copy, since the callers expect this.
  2755. ///--------------------------------------------------------------------------------------
  2756.  
  2757. SW_FUNC void SWWrapRectFromExtraBackFrame(
  2758.     SpriteWorldPtr    spriteWorldP,
  2759.     Rect            *dstRectP)
  2760. {
  2761.     FramePtr    srcFrameP = spriteWorldP->extraBackFrameP;
  2762.     FramePtr    dstFrameP = spriteWorldP->backFrameP;
  2763.     Rect        srcRect, tempSrcRect, tempDstRect;
  2764.     short        topClip=0, rightClip=0, bottomClip=0, leftClip=0;
  2765.     short        vertBackRectOffset, horizBackRectOffset;    
  2766.     
  2767.     SW_ASSERT(spriteWorldP != NULL);
  2768.     SW_ASSERT(srcFrameP->isFrameLocked);
  2769.     SW_ASSERT(dstFrameP->isFrameLocked);        
  2770.     
  2771.         // The code below is ripped from SWCalculateOffscreenScrollRect
  2772.         // It is modified to do a similar function for the extraBackFrameP.
  2773.     vertBackRectOffset = spriteWorldP->extraBackFrameP->frameRect.bottom * 
  2774.         (dstRectP->top / spriteWorldP->extraBackFrameP->frameRect.bottom);
  2775.     
  2776.     horizBackRectOffset = spriteWorldP->extraBackFrameP->frameRect.right *
  2777.         (dstRectP->left / spriteWorldP->extraBackFrameP->frameRect.right);
  2778.         
  2779.     srcRect.top = dstRectP->top - vertBackRectOffset;
  2780.     srcRect.bottom = dstRectP->bottom - vertBackRectOffset;
  2781.     srcRect.left = dstRectP->left - horizBackRectOffset;
  2782.     srcRect.right = dstRectP->right - horizBackRectOffset;
  2783.     
  2784.     // We must do the dstRect calculation below *after* the code above!
  2785.     
  2786.         // Make the tile's dest rect local to the offscreen area
  2787.     dstRectP->top -= spriteWorldP->vertScrollRectOffset;
  2788.     dstRectP->bottom -= spriteWorldP->vertScrollRectOffset;
  2789.     dstRectP->left -= spriteWorldP->horizScrollRectOffset;
  2790.     dstRectP->right -= spriteWorldP->horizScrollRectOffset;
  2791.     
  2792.         // Wrap dstRect to top or bottom of offscreen area
  2793.     if (dstRectP->bottom > dstFrameP->frameRect.bottom)
  2794.     {
  2795.         dstRectP->top -= dstFrameP->frameRect.bottom;
  2796.         dstRectP->bottom -= dstFrameP->frameRect.bottom;
  2797.     }
  2798.     else if (dstRectP->top < dstFrameP->frameRect.top)
  2799.     {
  2800.         dstRectP->top += dstFrameP->frameRect.bottom;
  2801.         dstRectP->bottom += dstFrameP->frameRect.bottom;
  2802.     }
  2803.     
  2804.         // Wrap dstRect to left or right side of offscreen area
  2805.     if (dstRectP->right > dstFrameP->frameRect.right)
  2806.     {
  2807.         dstRectP->left -= dstFrameP->frameRect.right;
  2808.         dstRectP->right -= dstFrameP->frameRect.right;
  2809.     }
  2810.     else if (dstRectP->left < dstFrameP->frameRect.left)
  2811.     {
  2812.         dstRectP->left += dstFrameP->frameRect.right;
  2813.         dstRectP->right += dstFrameP->frameRect.right;
  2814.     }
  2815.  
  2816.     
  2817.         // Clip the source rect, and save what we clipped for wrapping later //
  2818.     
  2819.         // clip off the top
  2820.     if (srcRect.top < srcFrameP->frameRect.top)
  2821.     {
  2822.         topClip = srcFrameP->frameRect.top - srcRect.top;
  2823.         srcRect.top += topClip;    
  2824.     }
  2825.     
  2826.         // clip off the bottom
  2827.     if (srcRect.bottom > srcFrameP->frameRect.bottom)
  2828.     {
  2829.         bottomClip = srcRect.bottom - srcFrameP->frameRect.bottom;
  2830.         srcRect.bottom -= bottomClip;
  2831.     }
  2832.     
  2833.         // clip off the left
  2834.     if (srcRect.left < srcFrameP->frameRect.left)
  2835.     {
  2836.         leftClip = srcFrameP->frameRect.left - srcRect.left;
  2837.         srcRect.left += leftClip;
  2838.     }
  2839.     
  2840.         // clip off the right
  2841.     if (srcRect.right > srcFrameP->frameRect.right)
  2842.     {
  2843.         rightClip = srcRect.right - srcFrameP->frameRect.right;
  2844.         srcRect.right -= rightClip;
  2845.     }
  2846.     
  2847.     
  2848.                     // Here we do the wrapping and drawing //
  2849.     
  2850.         // Draw top section //
  2851.     
  2852.     if (topClip)
  2853.     {
  2854.                 // Calculate top piece //
  2855.         
  2856.             // Wrap source rect to bottom side
  2857.         tempSrcRect.right = srcRect.right;                    // Copy clipped source rect
  2858.         tempSrcRect.left = srcRect.left;
  2859.         tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2860.         tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2861.         
  2862.             // Position dest rect at top side
  2863.         tempDstRect.top = dstRectP->top;
  2864.         tempDstRect.bottom = dstRectP->top + topClip;
  2865.         tempDstRect.left = dstRectP->left + leftClip;
  2866.         tempDstRect.right = dstRectP->right - rightClip;
  2867.         
  2868.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2869.         
  2870.         
  2871.         if (leftClip)    // Calculate top-left piece
  2872.         {
  2873.                 // Wrap source rect to lower-right corner
  2874.             tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2875.             tempSrcRect.right = srcFrameP->frameRect.right;
  2876.             tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2877.             tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2878.             
  2879.                 // Position dest rect at top-left corner
  2880.             tempDstRect.left = dstRectP->left;
  2881.             tempDstRect.top = dstRectP->top;
  2882.             tempDstRect.right = dstRectP->left + leftClip;
  2883.             tempDstRect.bottom = dstRectP->top + topClip;
  2884.             
  2885.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2886.         }
  2887.         else if (rightClip)        // Calculate top-right piece
  2888.         {
  2889.                 // Wrap source rect to lower-left corner
  2890.             tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2891.             tempSrcRect.left = srcFrameP->frameRect.left;
  2892.             tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2893.             tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2894.             
  2895.                 // Position dest rect at top-right corner
  2896.             tempDstRect.top = dstRectP->top;
  2897.             tempDstRect.right = dstRectP->right;
  2898.             tempDstRect.bottom = dstRectP->top + topClip;
  2899.             tempDstRect.left = dstRectP->right - rightClip;
  2900.             
  2901.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2902.         }
  2903.     }
  2904.     
  2905.     
  2906.             // Draw middle section //
  2907.     
  2908.         // Calculate main middle piece (not wrapped)
  2909.     tempDstRect.left = dstRectP->left + leftClip;
  2910.     tempDstRect.top = dstRectP->top + topClip;
  2911.     tempDstRect.right = dstRectP->right - rightClip;
  2912.     tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2913.     
  2914.     (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &srcRect, &tempDstRect);
  2915.     
  2916.     
  2917.     if (leftClip)    // Draw left piece
  2918.     {
  2919.             // Wrap source rect to right side
  2920.         tempSrcRect.top = srcRect.top;                // Copy clipped source rect
  2921.         tempSrcRect.bottom = srcRect.bottom;
  2922.         tempSrcRect.right = srcFrameP->frameRect.right;
  2923.         tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2924.         
  2925.             // Position dest rect at left side
  2926.         tempDstRect.left = dstRectP->left;
  2927.         tempDstRect.right = dstRectP->left + leftClip;
  2928.         tempDstRect.top = dstRectP->top + topClip;
  2929.         tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2930.         
  2931.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2932.     }
  2933.     else if (rightClip)        // Draw right piece
  2934.     {
  2935.             // Wrap source rect to left side
  2936.         tempSrcRect.top = srcRect.top;                // Copy clipped source rect
  2937.         tempSrcRect.bottom = srcRect.bottom;
  2938.         tempSrcRect.left = srcFrameP->frameRect.left;
  2939.         tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2940.         
  2941.             // Position dest rect at right side
  2942.         tempDstRect.right = dstRectP->right;
  2943.         tempDstRect.left = dstRectP->right - rightClip;
  2944.         tempDstRect.top = dstRectP->top + topClip;
  2945.         tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2946.         
  2947.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2948.     }
  2949.     
  2950.     
  2951.         // Draw bottom section //
  2952.     
  2953.     if (bottomClip)
  2954.     {
  2955.             // Calculate bottom piece //
  2956.         
  2957.             // Wrap source rect to top side
  2958.         tempSrcRect.right = srcRect.right;                // Copy clipped source rect
  2959.         tempSrcRect.left = srcRect.left;
  2960.         tempSrcRect.top = srcFrameP->frameRect.top;
  2961.         tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2962.         
  2963.             // Position dest rect at bottom side
  2964.         tempDstRect.bottom = dstRectP->bottom;
  2965.         tempDstRect.top = dstRectP->bottom - bottomClip;
  2966.         tempDstRect.left = dstRectP->left + leftClip;
  2967.         tempDstRect.right = dstRectP->right - rightClip;
  2968.  
  2969.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2970.         
  2971.         if (leftClip)     // Draw bottom-left piece
  2972.         {
  2973.                 // Wrap source rect to upper-right corner
  2974.             tempSrcRect.top = srcFrameP->frameRect.top;
  2975.             tempSrcRect.right = srcFrameP->frameRect.right;
  2976.             tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2977.             tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2978.             
  2979.                 // Position dest rect at bottom-left corner
  2980.             tempDstRect.bottom = dstRectP->bottom;
  2981.             tempDstRect.left = dstRectP->left;
  2982.             tempDstRect.top = dstRectP->bottom - bottomClip;
  2983.             tempDstRect.right = dstRectP->left + leftClip;
  2984.             
  2985.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2986.         }
  2987.         else if (rightClip)        // Draw bottom-right piece
  2988.         {
  2989.                 // Wrap source rect to upper-left corner
  2990.             tempSrcRect.top = srcFrameP->frameRect.top;
  2991.             tempSrcRect.left = srcFrameP->frameRect.left;
  2992.             tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2993.             tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2994.             
  2995.                 // Position dest rect at bottom-right corner
  2996.             tempDstRect.bottom = dstRectP->bottom;
  2997.             tempDstRect.right = dstRectP->right;
  2998.             tempDstRect.top = dstRectP->bottom - bottomClip;
  2999.             tempDstRect.left = dstRectP->right - rightClip;
  3000.             
  3001.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  3002.         }
  3003.     }
  3004. }
  3005.  
  3006.